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 < _data->num_tensors; 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 : /**
776 : * We now release allocated data only when _ml_tensors_data_destroy_internal() is called.
777 : * Be careful, if you update the number of tensors after creating the data handle,
778 : * you should manage the memories with changed index.
779 : */
780 0 : _info = (ml_tensors_info_s *) info;
781 0 : if (_info != NULL) {
782 0 : status = _ml_tensors_info_create_from (info, &_data->info);
783 0 : if (status != ML_ERROR_NONE) {
784 0 : _ml_error_report_continue
785 : ("Failed to create internal information handle for tensors data.");
786 0 : goto error;
787 : }
788 :
789 0 : G_LOCK_UNLESS_NOLOCK (*_info);
790 0 : _data->num_tensors = _info->info.num_tensors;
791 0 : for (i = 0; i < _data->num_tensors; i++) {
792 0 : _data->tensors[i].size = gst_tensors_info_get_size (&_info->info, i);
793 0 : _data->tensors[i].data = NULL;
794 : }
795 0 : G_UNLOCK_UNLESS_NOLOCK (*_info);
796 : }
797 :
798 0 : error:
799 0 : if (status == ML_ERROR_NONE) {
800 0 : *data = _data;
801 : } else {
802 0 : _ml_tensors_data_destroy_internal (_data, FALSE);
803 : }
804 :
805 0 : return status;
806 : }
807 :
808 : /**
809 : * @brief Clones the given tensor data frame from the given tensors data. (more info in nnstreamer.h)
810 : * @note Memory ptr for data buffer is copied. No new memory for data buffer is allocated.
811 : */
812 : int
813 0 : _ml_tensors_data_clone_no_alloc (const ml_tensors_data_s * data_src,
814 : ml_tensors_data_h * data)
815 : {
816 : int status;
817 : ml_tensors_data_s *_data;
818 :
819 0 : check_feature_state (ML_FEATURE);
820 :
821 0 : if (data == NULL)
822 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
823 : "The parameter, data, is NULL. It should be a valid ml_tensors_data_h handle, which is usually created by ml_tensors_data_create ().");
824 0 : if (data_src == NULL)
825 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
826 : "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).");
827 :
828 0 : status = _ml_tensors_data_create_no_alloc (data_src->info,
829 : (ml_tensors_data_h *) & _data);
830 0 : if (status != ML_ERROR_NONE)
831 0 : _ml_error_report_return_continue (status,
832 : "The call to _ml_tensors_data_create_no_alloc has failed with %d.",
833 : status);
834 :
835 0 : G_LOCK_UNLESS_NOLOCK (*_data);
836 :
837 0 : _data->num_tensors = data_src->num_tensors;
838 0 : memcpy (_data->tensors, data_src->tensors,
839 0 : sizeof (GstTensorMemory) * data_src->num_tensors);
840 :
841 0 : *data = _data;
842 0 : G_UNLOCK_UNLESS_NOLOCK (*_data);
843 0 : return ML_ERROR_NONE;
844 : }
845 :
846 : /**
847 : * @brief Allocates zero-initialized memory of the given size for the tensor at the specified index
848 : * in the tensor data structure, and sets the size value for that tensor.
849 : */
850 : static int
851 0 : _ml_tensor_data_alloc (ml_tensors_data_s * data, guint index, const size_t size)
852 : {
853 0 : if (!data || index >= data->num_tensors || size <= 0)
854 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
855 : "Invalid parameter: data is invalid, or index is out of range.");
856 :
857 0 : data->tensors[index].size = size;
858 0 : data->tensors[index].data = g_malloc0 (size);
859 0 : if (data->tensors[index].data == NULL)
860 0 : _ml_error_report_return (ML_ERROR_OUT_OF_MEMORY,
861 : "Failed to allocate memory for tensor data.");
862 :
863 0 : return ML_ERROR_NONE;
864 : }
865 :
866 : /**
867 : * @brief Copies the tensor data frame.
868 : */
869 : int
870 0 : ml_tensors_data_clone (const ml_tensors_data_h in, ml_tensors_data_h * out)
871 : {
872 : int status;
873 : unsigned int i;
874 0 : ml_tensors_data_s *_in, *_out = NULL;
875 :
876 0 : check_feature_state (ML_FEATURE);
877 :
878 0 : if (in == NULL)
879 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
880 : "The parameter, in, is NULL. It should be a valid ml_tensors_data_h handle, which is usually created by ml_tensors_data_create ().");
881 :
882 0 : if (out == NULL)
883 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
884 : "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);.");
885 :
886 0 : _in = (ml_tensors_data_s *) in;
887 0 : G_LOCK_UNLESS_NOLOCK (*_in);
888 :
889 0 : status = ml_tensors_data_create (_in->info, out);
890 0 : if (status != ML_ERROR_NONE) {
891 0 : _ml_loge ("Failed to create new handle to copy tensor data.");
892 0 : goto error;
893 : }
894 :
895 0 : _out = (ml_tensors_data_s *) (*out);
896 :
897 0 : for (i = 0; i < _out->num_tensors; ++i) {
898 0 : if (!_out->tensors[i].data) {
899 : /**
900 : * If tensor format is static, memory is already allocated.
901 : * However, flexible tensor is not. To copy raw data, allocate new memory here.
902 : */
903 0 : status = _ml_tensor_data_alloc (_out, i, _in->tensors[i].size);
904 0 : if (status != ML_ERROR_NONE) {
905 0 : goto error;
906 : }
907 : }
908 :
909 0 : memcpy (_out->tensors[i].data, _in->tensors[i].data, _in->tensors[i].size);
910 : }
911 :
912 0 : error:
913 0 : if (status != ML_ERROR_NONE) {
914 : /* Failed to create new data handle. */
915 0 : _ml_tensors_data_destroy_internal (_out, TRUE);
916 0 : *out = NULL;
917 : }
918 :
919 0 : G_UNLOCK_UNLESS_NOLOCK (*_in);
920 0 : return status;
921 : }
922 :
923 : /**
924 : * @brief Gets the tensors information of given tensor data frame.
925 : */
926 : int
927 0 : ml_tensors_data_get_info (const ml_tensors_data_h data,
928 : ml_tensors_info_h * info)
929 : {
930 : int status;
931 : ml_tensors_data_s *_data;
932 :
933 0 : check_feature_state (ML_FEATURE);
934 :
935 0 : if (data == NULL) {
936 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
937 : "The parameter, data, is NULL. It should be a valid ml_tensors_data_h handle, which is usually created by ml_tensors_data_create ().");
938 : }
939 :
940 0 : if (info == NULL) {
941 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
942 : "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);.");
943 : }
944 :
945 0 : _data = (ml_tensors_data_s *) data;
946 0 : G_LOCK_UNLESS_NOLOCK (*_data);
947 :
948 0 : status = _ml_tensors_info_create_from (_data->info, info);
949 0 : if (status != ML_ERROR_NONE) {
950 0 : _ml_error_report_continue
951 : ("Failed to get the tensor information from data handle.");
952 : }
953 :
954 0 : G_UNLOCK_UNLESS_NOLOCK (*_data);
955 0 : return status;
956 : }
957 :
958 : /**
959 : * @brief Allocates a tensor data frame with the given tensors info. (more info in nnstreamer.h)
960 : */
961 : int
962 0 : ml_tensors_data_create (const ml_tensors_info_h info, ml_tensors_data_h * data)
963 : {
964 0 : int status = ML_ERROR_NONE;
965 0 : ml_tensors_info_s *_info = NULL;
966 0 : ml_tensors_data_s *_data = NULL;
967 : guint i;
968 : bool valid;
969 :
970 0 : check_feature_state (ML_FEATURE);
971 :
972 0 : if (info == NULL)
973 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
974 : "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().");
975 0 : if (data == NULL)
976 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
977 : "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);.");
978 :
979 0 : status = ml_tensors_info_validate (info, &valid);
980 0 : if (status != ML_ERROR_NONE)
981 0 : _ml_error_report_return_continue (status,
982 : "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.");
983 0 : if (!valid)
984 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
985 : "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.");
986 :
987 : status =
988 0 : _ml_tensors_data_create_no_alloc (info, (ml_tensors_data_h *) & _data);
989 :
990 0 : if (status != ML_ERROR_NONE) {
991 0 : _ml_error_report_return_continue (status,
992 : "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.",
993 : status);
994 : }
995 :
996 0 : _info = (ml_tensors_info_s *) info;
997 0 : if (_info->info.format == _NNS_TENSOR_FORMAT_STATIC) {
998 0 : for (i = 0; i < _data->num_tensors; i++) {
999 0 : status = _ml_tensor_data_alloc (_data, i, _data->tensors[i].size);
1000 0 : if (status != ML_ERROR_NONE)
1001 0 : goto error;
1002 : }
1003 : } else {
1004 0 : _ml_logw
1005 : ("[ml_tensors_data_create] format is not static, skipping tensor memory allocation. Use ml_tensors_data_set_tensor_data() to update data buffer.");
1006 : }
1007 :
1008 0 : error:
1009 0 : if (status == ML_ERROR_NONE) {
1010 0 : *data = _data;
1011 : } else {
1012 0 : _ml_tensors_data_destroy_internal (_data, TRUE);
1013 : }
1014 :
1015 0 : return status;
1016 : }
1017 :
1018 : /**
1019 : * @brief Gets a tensor data of given handle.
1020 : */
1021 : int
1022 0 : ml_tensors_data_get_tensor_data (ml_tensors_data_h data, unsigned int index,
1023 : void **raw_data, size_t *data_size)
1024 : {
1025 : ml_tensors_data_s *_data;
1026 0 : int status = ML_ERROR_NONE;
1027 :
1028 0 : check_feature_state (ML_FEATURE);
1029 :
1030 0 : if (data == NULL)
1031 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1032 : "The parameter, data, is NULL. It should be a valid ml_tensors_data_h handle, which is usually created by ml_tensors_data_create ().");
1033 0 : if (raw_data == NULL)
1034 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1035 : "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.");
1036 0 : if (data_size == NULL)
1037 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1038 : "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.");
1039 :
1040 0 : _data = (ml_tensors_data_s *) data;
1041 0 : G_LOCK_UNLESS_NOLOCK (*_data);
1042 :
1043 0 : if (_data->num_tensors <= index) {
1044 0 : _ml_error_report
1045 : ("The parameter, index, is out of bound. The number of tensors of 'data' is %u while you requested %u'th tensor (index = %u).",
1046 : _data->num_tensors, index, index);
1047 0 : status = ML_ERROR_INVALID_PARAMETER;
1048 0 : goto report;
1049 : }
1050 :
1051 0 : *raw_data = _data->tensors[index].data;
1052 0 : *data_size = _data->tensors[index].size;
1053 :
1054 0 : report:
1055 0 : G_UNLOCK_UNLESS_NOLOCK (*_data);
1056 0 : return status;
1057 : }
1058 :
1059 : /**
1060 : * @brief Copies a tensor data to given handle.
1061 : */
1062 : int
1063 0 : ml_tensors_data_set_tensor_data (ml_tensors_data_h data, unsigned int index,
1064 : const void *raw_data, const size_t data_size)
1065 : {
1066 0 : ml_tensors_info_s *_info = NULL;
1067 : ml_tensors_data_s *_data;
1068 0 : int status = ML_ERROR_NONE;
1069 :
1070 0 : check_feature_state (ML_FEATURE);
1071 :
1072 0 : if (data == NULL)
1073 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1074 : "The parameter, data, is NULL. It should be a valid ml_tensors_data_h handle, which is usually created by ml_tensors_data_create ().");
1075 0 : if (raw_data == NULL)
1076 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1077 : "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].",
1078 : index);
1079 :
1080 0 : _data = (ml_tensors_data_s *) data;
1081 0 : G_LOCK_UNLESS_NOLOCK (*_data);
1082 :
1083 0 : if (_data->num_tensors <= index) {
1084 0 : _ml_error_report
1085 : ("The parameter, index, is out of bound. The number of tensors of 'data' is %u, while you've requested index of %u.",
1086 : _data->num_tensors, index);
1087 0 : status = ML_ERROR_INVALID_PARAMETER;
1088 0 : goto report;
1089 : }
1090 :
1091 : /**
1092 : * By default, the tensor format is _NNS_TENSOR_FORMAT_STATIC.
1093 : * In this case, memory allocation and the setting of _data->tensors[index].size
1094 : * are already handled in ml_tensors_data_create().
1095 : * So for the STATIC format, both the `size` and `data` pointer should already be valid here.
1096 : *
1097 : * For FLEXIBLE format, memory may not be allocated yet and will be handled here.
1098 : */
1099 0 : _info = (ml_tensors_info_s *) _data->info;
1100 0 : if (_info && _info->info.format != _NNS_TENSOR_FORMAT_STATIC) {
1101 0 : if (!_data->tensors[index].data ||
1102 0 : _data->tensors[index].size != data_size) {
1103 0 : _ml_logw
1104 : ("Memory allocation was not performed in ml_tensor_data_create() when tensor format is flexible.");
1105 :
1106 0 : g_clear_pointer (&_data->tensors[index].data, g_free);
1107 :
1108 0 : status = _ml_tensor_data_alloc (_data, index, data_size);
1109 0 : if (status != ML_ERROR_NONE) {
1110 0 : goto report;
1111 : }
1112 : }
1113 : }
1114 :
1115 0 : if (data_size <= 0 || _data->tensors[index].size < data_size) {
1116 0 : _ml_error_report
1117 : ("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).",
1118 : data_size, index, _data->tensors[index].size);
1119 0 : status = ML_ERROR_INVALID_PARAMETER;
1120 0 : goto report;
1121 : }
1122 :
1123 0 : if (_data->tensors[index].data != raw_data)
1124 0 : memcpy (_data->tensors[index].data, raw_data, data_size);
1125 :
1126 0 : report:
1127 0 : G_UNLOCK_UNLESS_NOLOCK (*_data);
1128 0 : return status;
1129 : }
1130 :
1131 : /**
1132 : * @brief Copies tensor meta info.
1133 : */
1134 : int
1135 0 : ml_tensors_info_clone (ml_tensors_info_h dest, const ml_tensors_info_h src)
1136 : {
1137 : ml_tensors_info_s *dest_info, *src_info;
1138 0 : int status = ML_ERROR_NONE;
1139 :
1140 0 : check_feature_state (ML_FEATURE);
1141 :
1142 0 : dest_info = (ml_tensors_info_s *) dest;
1143 0 : src_info = (ml_tensors_info_s *) src;
1144 :
1145 0 : if (!dest_info)
1146 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1147 : "The parameter, dest, is NULL. It should be an allocated handle (ml_tensors_info_h), usually allocated by ml_tensors_info_create ().");
1148 0 : if (!src_info)
1149 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1150 : "The parameter, src, is NULL. It should be a handle (ml_tensors_info_h) with valid data.");
1151 :
1152 0 : G_LOCK_UNLESS_NOLOCK (*dest_info);
1153 0 : G_LOCK_UNLESS_NOLOCK (*src_info);
1154 :
1155 0 : if (gst_tensors_info_validate (&src_info->info)) {
1156 0 : dest_info->is_extended = src_info->is_extended;
1157 0 : gst_tensors_info_copy (&dest_info->info, &src_info->info);
1158 : } else {
1159 0 : _ml_error_report
1160 : ("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.",
1161 : ML_TENSOR_SIZE_LIMIT);
1162 0 : status = ML_ERROR_INVALID_PARAMETER;
1163 : }
1164 :
1165 0 : G_UNLOCK_UNLESS_NOLOCK (*src_info);
1166 0 : G_UNLOCK_UNLESS_NOLOCK (*dest_info);
1167 :
1168 0 : return status;
1169 : }
1170 :
1171 : /**
1172 : * @brief Replaces string.
1173 : * This function deallocates the input source string.
1174 : * This is copied from nnstreamer/tensor_common.c by the nnstreamer maintainer.
1175 : * @param[in] source The input string. This will be freed when returning the replaced string.
1176 : * @param[in] what The string to search for.
1177 : * @param[in] to The string to be replaced.
1178 : * @param[in] delimiters The characters which specify the place to split the string. Set NULL to replace all matched string.
1179 : * @param[out] count The count of replaced. Set NULL if it is unnecessary.
1180 : * @return Newly allocated string. The returned string should be freed with g_free().
1181 : */
1182 : gchar *
1183 0 : _ml_replace_string (gchar * source, const gchar * what, const gchar * to,
1184 : const gchar * delimiters, guint * count)
1185 : {
1186 : GString *builder;
1187 : gchar *start, *pos, *result;
1188 0 : guint changed = 0;
1189 : gsize len;
1190 :
1191 0 : g_return_val_if_fail (source, NULL);
1192 0 : g_return_val_if_fail (what && to, source);
1193 :
1194 0 : len = strlen (what);
1195 0 : start = source;
1196 :
1197 0 : builder = g_string_new (NULL);
1198 0 : while ((pos = g_strstr_len (start, -1, what)) != NULL) {
1199 0 : gboolean skip = FALSE;
1200 :
1201 0 : if (delimiters) {
1202 : const gchar *s;
1203 : gchar *prev, *next;
1204 : gboolean prev_split, next_split;
1205 :
1206 0 : prev = next = NULL;
1207 0 : prev_split = next_split = FALSE;
1208 :
1209 0 : if (pos != source)
1210 0 : prev = pos - 1;
1211 0 : if (*(pos + len) != '\0')
1212 0 : next = pos + len;
1213 :
1214 0 : for (s = delimiters; *s != '\0'; ++s) {
1215 0 : if (!prev || *s == *prev)
1216 0 : prev_split = TRUE;
1217 0 : if (!next || *s == *next)
1218 0 : next_split = TRUE;
1219 0 : if (prev_split && next_split)
1220 0 : break;
1221 : }
1222 :
1223 0 : if (!prev_split || !next_split)
1224 0 : skip = TRUE;
1225 : }
1226 :
1227 0 : builder = g_string_append_len (builder, start, pos - start);
1228 :
1229 : /* replace string if found */
1230 0 : if (skip)
1231 0 : builder = g_string_append_len (builder, pos, len);
1232 : else
1233 0 : builder = g_string_append (builder, to);
1234 :
1235 0 : start = pos + len;
1236 0 : if (!skip)
1237 0 : changed++;
1238 : }
1239 :
1240 : /* append remains */
1241 0 : builder = g_string_append (builder, start);
1242 0 : result = g_string_free (builder, FALSE);
1243 :
1244 0 : if (count)
1245 0 : *count = changed;
1246 :
1247 0 : g_free (source);
1248 0 : return result;
1249 : }
1250 :
1251 : /**
1252 : * @brief Converts predefined entity.
1253 : */
1254 : gchar *
1255 0 : _ml_convert_predefined_entity (const gchar * str)
1256 : {
1257 0 : gchar *converted = g_strdup (str);
1258 :
1259 : #if defined(__ANDROID__)
1260 : {
1261 : extern const char *nnstreamer_native_get_data_path (void);
1262 :
1263 : const char *data_path = nnstreamer_native_get_data_path ();
1264 :
1265 : converted = _ml_replace_string (converted, "@APP_DATA_PATH@", data_path,
1266 : NULL, NULL);
1267 : }
1268 : #endif
1269 :
1270 0 : return converted;
1271 : }
1272 :
1273 : /**
1274 : * @brief error reporting infra
1275 : */
1276 : #define _ML_ERRORMSG_LENGTH (4096U)
1277 : static char errormsg[_ML_ERRORMSG_LENGTH] = { 0 }; /* one page limit */
1278 :
1279 : static int reported = 0;
1280 : G_LOCK_DEFINE_STATIC (errlock);
1281 :
1282 : /**
1283 : * @brief public API function of error reporting.
1284 : */
1285 : const char *
1286 0 : ml_error (void)
1287 : {
1288 0 : G_LOCK (errlock);
1289 0 : if (reported != 0) {
1290 0 : errormsg[0] = '\0';
1291 0 : reported = 0;
1292 : }
1293 0 : if (errormsg[0] == '\0') {
1294 0 : G_UNLOCK (errlock);
1295 0 : return NULL;
1296 : }
1297 :
1298 0 : reported = 1;
1299 :
1300 0 : G_UNLOCK (errlock);
1301 0 : return errormsg;
1302 : }
1303 :
1304 : /**
1305 : * @brief Internal interface to write messages for ml_error()
1306 : */
1307 : void
1308 3 : _ml_error_report_ (const char *fmt, ...)
1309 : {
1310 : int n;
1311 : va_list arg_ptr;
1312 3 : G_LOCK (errlock);
1313 :
1314 3 : va_start (arg_ptr, fmt);
1315 3 : n = vsnprintf (errormsg, _ML_ERRORMSG_LENGTH, fmt, arg_ptr);
1316 3 : va_end (arg_ptr);
1317 :
1318 3 : if (n > _ML_ERRORMSG_LENGTH) {
1319 0 : errormsg[_ML_ERRORMSG_LENGTH - 2] = '.';
1320 0 : errormsg[_ML_ERRORMSG_LENGTH - 3] = '.';
1321 0 : errormsg[_ML_ERRORMSG_LENGTH - 4] = '.';
1322 : }
1323 :
1324 3 : _ml_loge ("%s", errormsg);
1325 :
1326 3 : reported = 0;
1327 :
1328 3 : G_UNLOCK (errlock);
1329 3 : }
1330 :
1331 : /**
1332 : * @brief Internal interface to write messages for ml_error(), relaying previously reported errors.
1333 : */
1334 : void
1335 0 : _ml_error_report_continue_ (const char *fmt, ...)
1336 : {
1337 0 : size_t cursor = 0;
1338 : va_list arg_ptr;
1339 : char buf[_ML_ERRORMSG_LENGTH];
1340 0 : G_LOCK (errlock);
1341 :
1342 : /* Check if there is a message to relay */
1343 0 : if (reported == 0) {
1344 0 : cursor = strlen (errormsg);
1345 0 : if (cursor < (_ML_ERRORMSG_LENGTH - 1)) {
1346 0 : errormsg[cursor] = '\n';
1347 0 : errormsg[cursor + 1] = '\0';
1348 0 : cursor++;
1349 : }
1350 : } else {
1351 0 : errormsg[0] = '\0';
1352 : }
1353 :
1354 0 : va_start (arg_ptr, fmt);
1355 0 : vsnprintf (buf, _ML_ERRORMSG_LENGTH - 1, fmt, arg_ptr);
1356 0 : _ml_loge ("%s", buf);
1357 :
1358 0 : memcpy (errormsg + cursor, buf, _ML_ERRORMSG_LENGTH - strlen (errormsg) - 1);
1359 0 : if (strlen (errormsg) >= (_ML_ERRORMSG_LENGTH - 2)) {
1360 0 : errormsg[_ML_ERRORMSG_LENGTH - 2] = '.';
1361 0 : errormsg[_ML_ERRORMSG_LENGTH - 3] = '.';
1362 0 : errormsg[_ML_ERRORMSG_LENGTH - 4] = '.';
1363 : }
1364 :
1365 0 : va_end (arg_ptr);
1366 :
1367 0 : errormsg[_ML_ERRORMSG_LENGTH - 1] = '\0';
1368 0 : reported = 0;
1369 0 : G_UNLOCK (errlock);
1370 0 : }
1371 :
1372 : static const char *strerrors[] = {
1373 : [0] = "Not an error",
1374 : [EINVAL] =
1375 : "Invalid parameters are given to a function. Check parameter values. (EINVAL)",
1376 : };
1377 :
1378 : /**
1379 : * @brief public API function of error code descriptions
1380 : */
1381 : const char *
1382 0 : ml_strerror (int errnum)
1383 : {
1384 0 : int size = sizeof (strerrors) / sizeof (strerrors[0]);
1385 :
1386 0 : if (errnum < 0)
1387 0 : errnum = errnum * -1;
1388 :
1389 0 : if (errnum == 0 || errnum >= size)
1390 0 : return NULL;
1391 0 : return strerrors[errnum];
1392 : }
1393 :
1394 : /**
1395 : * @brief Internal function to check the handle is valid.
1396 : */
1397 : static bool
1398 0 : _ml_info_is_valid (gpointer handle, ml_info_type_e expected)
1399 : {
1400 : ml_info_type_e current;
1401 :
1402 0 : if (!handle)
1403 0 : return false;
1404 :
1405 : /* The first field should be an enum value of ml_info_type_e. */
1406 0 : current = *((ml_info_type_e *) handle);
1407 0 : if (current != expected)
1408 0 : return false;
1409 :
1410 0 : switch (current) {
1411 0 : case ML_INFO_TYPE_OPTION:
1412 : case ML_INFO_TYPE_INFORMATION:
1413 : {
1414 0 : ml_info_s *_info = (ml_info_s *) handle;
1415 :
1416 0 : if (!_info->table)
1417 0 : return false;
1418 :
1419 0 : break;
1420 : }
1421 0 : case ML_INFO_TYPE_INFORMATION_LIST:
1422 0 : break;
1423 0 : default:
1424 : /* Unknown type */
1425 0 : return false;
1426 : }
1427 :
1428 0 : return true;
1429 : }
1430 :
1431 : /**
1432 : * @brief Internal function for destroy value of option table
1433 : */
1434 : static void
1435 0 : _ml_info_value_free (gpointer data)
1436 : {
1437 : ml_info_value_s *_value;
1438 :
1439 0 : _value = (ml_info_value_s *) data;
1440 0 : if (_value) {
1441 0 : if (_value->destroy)
1442 0 : _value->destroy (_value->value);
1443 0 : g_free (_value);
1444 : }
1445 0 : }
1446 :
1447 : /**
1448 : * @brief Internal function for create ml_info
1449 : */
1450 : static ml_info_s *
1451 0 : _ml_info_create (ml_info_type_e type)
1452 : {
1453 : ml_info_s *info;
1454 :
1455 0 : info = g_new0 (ml_info_s, 1);
1456 0 : if (info == NULL) {
1457 0 : _ml_error_report
1458 : ("Failed to allocate memory for the ml_info. Out of memory?");
1459 0 : return NULL;
1460 : }
1461 :
1462 0 : info->type = type;
1463 0 : info->table =
1464 0 : g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
1465 : _ml_info_value_free);
1466 0 : if (info->table == NULL) {
1467 0 : _ml_error_report
1468 : ("Failed to allocate memory for the table of ml_info. Out of memory?");
1469 0 : g_free (info);
1470 0 : return NULL;
1471 : }
1472 :
1473 0 : return info;
1474 : }
1475 :
1476 : /**
1477 : * @brief Internal function for destroy ml_info
1478 : */
1479 : static void
1480 0 : _ml_info_destroy (gpointer data)
1481 : {
1482 0 : ml_info_s *info = (ml_info_s *) data;
1483 :
1484 0 : if (!info)
1485 0 : return;
1486 :
1487 0 : info->type = ML_INFO_TYPE_UNKNOWN;
1488 :
1489 0 : if (info->table) {
1490 0 : g_hash_table_destroy (info->table);
1491 0 : info->table = NULL;
1492 : }
1493 :
1494 0 : g_free (info);
1495 0 : return;
1496 : }
1497 :
1498 : /**
1499 : * @brief Internal function for set value of given ml_info
1500 : */
1501 : static int
1502 0 : _ml_info_set_value (ml_info_s * info, const char *key, void *value,
1503 : ml_data_destroy_cb destroy)
1504 : {
1505 : ml_info_value_s *info_value;
1506 :
1507 0 : if (!STR_IS_VALID (key))
1508 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1509 : "The parameter, 'key' is invalid. It should be a valid string.");
1510 :
1511 0 : if (!info || !value)
1512 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1513 : "The parameter, 'info' or 'value' is NULL. It should be a valid ml_info and value.");
1514 :
1515 0 : info_value = g_new0 (ml_info_value_s, 1);
1516 0 : if (!info_value)
1517 0 : _ml_error_report_return (ML_ERROR_OUT_OF_MEMORY,
1518 : "Failed to allocate memory for the info value. Out of memory?");
1519 :
1520 0 : info_value->value = value;
1521 0 : info_value->destroy = destroy;
1522 0 : g_hash_table_insert (info->table, g_strdup (key), (gpointer) info_value);
1523 :
1524 0 : return ML_ERROR_NONE;
1525 : }
1526 :
1527 : /**
1528 : * @brief Internal function for get value of given ml_info
1529 : */
1530 : static int
1531 0 : _ml_info_get_value (ml_info_s * info, const char *key, void **value)
1532 : {
1533 : ml_info_value_s *info_value;
1534 :
1535 0 : if (!info || !key || !value)
1536 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1537 : "The parameter, 'info', 'key' or 'value' is NULL. It should be a valid ml_info, key and value.");
1538 :
1539 0 : info_value = g_hash_table_lookup (info->table, key);
1540 0 : if (!info_value) {
1541 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1542 : "Failed to find a value of key '%s', invalid key string?", key);
1543 : }
1544 :
1545 0 : *value = info_value->value;
1546 :
1547 0 : return ML_ERROR_NONE;
1548 : }
1549 :
1550 : /**
1551 : * @brief Creates an option and returns the instance a handle.
1552 : */
1553 : int
1554 0 : ml_option_create (ml_option_h * option)
1555 : {
1556 0 : ml_info_s *_option = NULL;
1557 :
1558 0 : check_feature_state (ML_FEATURE);
1559 :
1560 0 : if (!option) {
1561 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1562 : "The parameter, 'option' is NULL. It should be a valid ml_option_h");
1563 : }
1564 :
1565 0 : _option = _ml_info_create (ML_INFO_TYPE_OPTION);
1566 0 : if (_option == NULL)
1567 0 : _ml_error_report_return (ML_ERROR_OUT_OF_MEMORY,
1568 : "Failed to allocate memory for the option handle. Out of memory?");
1569 :
1570 0 : *option = _option;
1571 0 : return ML_ERROR_NONE;
1572 : }
1573 :
1574 : /**
1575 : * @brief Frees the given handle of a ml_option.
1576 : */
1577 : int
1578 0 : ml_option_destroy (ml_option_h option)
1579 : {
1580 0 : check_feature_state (ML_FEATURE);
1581 :
1582 0 : if (!option) {
1583 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1584 : "The parameter, 'option' is NULL. It should be a valid ml_option_h, which should be created by ml_option_create().");
1585 : }
1586 :
1587 0 : if (!_ml_info_is_valid (option, ML_INFO_TYPE_OPTION))
1588 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1589 : "The parameter, 'option' is not a ml-option handle.");
1590 :
1591 0 : _ml_info_destroy (option);
1592 :
1593 0 : return ML_ERROR_NONE;
1594 : }
1595 :
1596 : /**
1597 : * @brief Set key-value pair in given option handle. Note that if duplicated key is given, the value is updated with the new one.
1598 : * If some options are changed or there are newly added options, please modify below description.
1599 : * The list of valid key-values are:
1600 : *
1601 : * key (char *) || value (expected type (pointer))
1602 : * ---------------------------------------------------------
1603 : * "framework_name" || explicit name of framework (char *)
1604 : * ...
1605 : */
1606 : int
1607 0 : ml_option_set (ml_option_h option, const char *key, void *value,
1608 : ml_data_destroy_cb destroy)
1609 : {
1610 0 : check_feature_state (ML_FEATURE);
1611 :
1612 0 : if (!option) {
1613 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1614 : "The parameter, 'option' is NULL. It should be a valid ml_option_h, which should be created by ml_option_create().");
1615 : }
1616 :
1617 0 : if (!key) {
1618 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1619 : "The parameter, 'key' is NULL. It should be a valid const char*");
1620 : }
1621 :
1622 0 : if (!value) {
1623 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1624 : "The parameter, 'value' is NULL. It should be a valid void*");
1625 : }
1626 :
1627 0 : if (!_ml_info_is_valid (option, ML_INFO_TYPE_OPTION))
1628 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1629 : "The parameter, 'option' is not a ml-option handle.");
1630 :
1631 0 : return _ml_info_set_value ((ml_info_s *) option, key, value, destroy);
1632 : }
1633 :
1634 : /**
1635 : * @brief Gets a value of key in ml_option instance.
1636 : */
1637 : int
1638 0 : ml_option_get (ml_option_h option, const char *key, void **value)
1639 : {
1640 0 : check_feature_state (ML_FEATURE);
1641 :
1642 0 : if (!option) {
1643 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1644 : "The parameter, 'option' is NULL. It should be a valid ml_option_h, which should be created by ml_option_create().");
1645 : }
1646 :
1647 0 : if (!key) {
1648 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1649 : "The parameter, 'key' is NULL. It should be a valid const char*");
1650 : }
1651 :
1652 0 : if (!value) {
1653 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1654 : "The parameter, 'value' is NULL. It should be a valid void**");
1655 : }
1656 :
1657 0 : if (!_ml_info_is_valid (option, ML_INFO_TYPE_OPTION))
1658 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1659 : "The parameter, 'option' is not a ml-option handle.");
1660 :
1661 0 : return _ml_info_get_value ((ml_info_s *) option, key, value);
1662 : }
1663 :
1664 : /**
1665 : * @brief Creates an ml_information instance and returns the handle.
1666 : */
1667 : int
1668 0 : _ml_information_create (ml_information_h * info)
1669 : {
1670 0 : ml_info_s *_info = NULL;
1671 :
1672 0 : check_feature_state (ML_FEATURE);
1673 :
1674 0 : if (!info) {
1675 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1676 : "The parameter, 'info' is NULL. It should be a valid ml_information_h");
1677 : }
1678 :
1679 0 : _info = _ml_info_create (ML_INFO_TYPE_INFORMATION);
1680 0 : if (!_info)
1681 0 : _ml_error_report_return (ML_ERROR_OUT_OF_MEMORY,
1682 : "Failed to allocate memory for the info handle. Out of memory?");
1683 :
1684 0 : *info = _info;
1685 0 : return ML_ERROR_NONE;
1686 : }
1687 :
1688 : /**
1689 : * @brief Set key-value pair in given information handle.
1690 : * @note If duplicated key is given, the value is updated with the new one.
1691 : */
1692 : int
1693 0 : _ml_information_set (ml_information_h information, const char *key, void *value,
1694 : ml_data_destroy_cb destroy)
1695 : {
1696 0 : check_feature_state (ML_FEATURE);
1697 :
1698 0 : if (!information) {
1699 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1700 : "The parameter, 'information' is NULL. It should be a valid ml_information_h, which should be created by ml_information_create().");
1701 : }
1702 :
1703 0 : if (!key) {
1704 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1705 : "The parameter, 'key' is NULL. It should be a valid const char*");
1706 : }
1707 :
1708 0 : if (!value) {
1709 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1710 : "The parameter, 'value' is NULL. It should be a valid void*");
1711 : }
1712 :
1713 0 : if (!_ml_info_is_valid (information, ML_INFO_TYPE_INFORMATION))
1714 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1715 : "The parameter, 'information' is not a ml-information handle.");
1716 :
1717 0 : return _ml_info_set_value ((ml_info_s *) information, key, value, destroy);
1718 : }
1719 :
1720 : /**
1721 : * @brief Internal function to iterate ml-information.
1722 : */
1723 : static void
1724 0 : _ml_information_iter_internal (gpointer key, gpointer value, gpointer user_data)
1725 : {
1726 0 : ml_info_iter_data_s *iter = (ml_info_iter_data_s *) user_data;
1727 0 : ml_info_value_s *info_value = (ml_info_value_s *) value;
1728 :
1729 0 : iter->callback (key, info_value->value, iter->user_data);
1730 0 : }
1731 :
1732 : /**
1733 : * @brief Iterates the key and value of each pair in ml-information.
1734 : */
1735 : int
1736 0 : ml_information_iterate (ml_information_h ml_info,
1737 : ml_information_iterate_cb cb, void *user_data)
1738 : {
1739 : ml_info_s *_info;
1740 : ml_info_iter_data_s *iter;
1741 :
1742 0 : check_feature_state (ML_FEATURE);
1743 :
1744 0 : if (!_ml_info_is_valid (ml_info, ML_INFO_TYPE_INFORMATION)) {
1745 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1746 : "The parameter, 'ml_info' is not a ml-information handle.");
1747 : }
1748 :
1749 0 : if (!cb) {
1750 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1751 : "The parameter, 'cb' is NULL. It should be a valid function.");
1752 : }
1753 :
1754 0 : _info = (ml_info_s *) ml_info;
1755 :
1756 0 : iter = g_new0 (ml_info_iter_data_s, 1);
1757 0 : if (!iter) {
1758 0 : _ml_error_report_return (ML_ERROR_OUT_OF_MEMORY,
1759 : "Failed to allocate memory for the iteration. Out of memory?");
1760 : }
1761 :
1762 0 : iter->callback = cb;
1763 0 : iter->user_data = user_data;
1764 :
1765 0 : g_hash_table_foreach (_info->table, _ml_information_iter_internal, iter);
1766 0 : g_free (iter);
1767 :
1768 0 : return ML_ERROR_NONE;
1769 : }
1770 :
1771 : /**
1772 : * @brief Frees the given handle of a ml_information.
1773 : */
1774 : int
1775 0 : ml_information_destroy (ml_information_h information)
1776 : {
1777 0 : check_feature_state (ML_FEATURE);
1778 :
1779 0 : if (!information) {
1780 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1781 : "The parameter, 'information' is NULL. It should be a valid ml_information_h, which should be created by ml_information_create().");
1782 : }
1783 :
1784 0 : if (!_ml_info_is_valid (information, ML_INFO_TYPE_INFORMATION))
1785 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1786 : "The parameter, 'information' is not a ml-information handle.");
1787 :
1788 0 : _ml_info_destroy (information);
1789 :
1790 0 : return ML_ERROR_NONE;
1791 : }
1792 :
1793 : /**
1794 : * @brief Gets the value corresponding to the given key in ml_information instance.
1795 : */
1796 : int
1797 0 : ml_information_get (ml_information_h information, const char *key, void **value)
1798 : {
1799 0 : check_feature_state (ML_FEATURE);
1800 :
1801 0 : if (!information) {
1802 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1803 : "The parameter, 'information' is NULL. It should be a valid ml_information_h, which should be created by ml_information_create().");
1804 : }
1805 :
1806 0 : if (!key) {
1807 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1808 : "The parameter, 'key' is NULL. It should be a valid const char*");
1809 : }
1810 :
1811 0 : if (!value) {
1812 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1813 : "The parameter, 'value' is NULL. It should be a valid void**");
1814 : }
1815 :
1816 0 : if (!_ml_info_is_valid (information, ML_INFO_TYPE_INFORMATION))
1817 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1818 : "The parameter, 'information' is not a ml-information handle.");
1819 :
1820 0 : return _ml_info_get_value ((ml_info_s *) information, key, value);
1821 : }
1822 :
1823 : /**
1824 : * @brief Creates an ml-information-list instance and returns the handle.
1825 : */
1826 : int
1827 0 : _ml_information_list_create (ml_information_list_h * list)
1828 : {
1829 : ml_info_list_s *_info_list;
1830 :
1831 0 : check_feature_state (ML_FEATURE);
1832 :
1833 0 : if (!list)
1834 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1835 : "The parameter, 'list' is NULL. It should be a valid ml_information_list_h.");
1836 :
1837 0 : _info_list = g_try_new0 (ml_info_list_s, 1);
1838 0 : if (!_info_list) {
1839 0 : _ml_error_report_return (ML_ERROR_OUT_OF_MEMORY,
1840 : "Failed to allocate memory for ml_information_list_h. Out of memory?");
1841 : }
1842 :
1843 0 : _info_list->type = ML_INFO_TYPE_INFORMATION_LIST;
1844 :
1845 0 : *list = _info_list;
1846 0 : return ML_ERROR_NONE;
1847 : }
1848 :
1849 : /**
1850 : * @brief Adds an ml-information into ml-information-list.
1851 : */
1852 : int
1853 0 : _ml_information_list_add (ml_information_list_h list, ml_information_h info)
1854 : {
1855 : ml_info_list_s *_info_list;
1856 :
1857 0 : check_feature_state (ML_FEATURE);
1858 :
1859 0 : if (!_ml_info_is_valid (list, ML_INFO_TYPE_INFORMATION_LIST)) {
1860 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1861 : "The parameter, 'list' is invalid. It should be a valid ml_information_list_h, which should be created by ml_information_list_create().");
1862 : }
1863 :
1864 0 : if (!_ml_info_is_valid (info, ML_INFO_TYPE_OPTION) &&
1865 0 : !_ml_info_is_valid (info, ML_INFO_TYPE_INFORMATION)) {
1866 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1867 : "The parameter, 'info' is invalid. It should be a valid ml_information_h, which should be created by ml_information_create().");
1868 : }
1869 :
1870 0 : _info_list = (ml_info_list_s *) list;
1871 0 : _info_list->info = g_slist_append (_info_list->info, info);
1872 :
1873 0 : return ML_ERROR_NONE;
1874 : }
1875 :
1876 : /**
1877 : * @brief Destroys the ml-information-list instance.
1878 : */
1879 : int
1880 0 : ml_information_list_destroy (ml_information_list_h list)
1881 : {
1882 : ml_info_list_s *_info_list;
1883 :
1884 0 : check_feature_state (ML_FEATURE);
1885 :
1886 0 : if (!_ml_info_is_valid (list, ML_INFO_TYPE_INFORMATION_LIST)) {
1887 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1888 : "The parameter, 'list' is invalid. It should be a valid ml_information_list_h, which should be created by ml_information_list_create().");
1889 : }
1890 :
1891 0 : _info_list = (ml_info_list_s *) list;
1892 0 : g_slist_free_full (_info_list->info, _ml_info_destroy);
1893 0 : g_free (_info_list);
1894 :
1895 0 : return ML_ERROR_NONE;
1896 : }
1897 :
1898 : /**
1899 : * @brief Gets the number of ml-information in ml-information-list instance.
1900 : */
1901 : int
1902 0 : ml_information_list_length (ml_information_list_h list, unsigned int *length)
1903 : {
1904 : ml_info_list_s *_info_list;
1905 :
1906 0 : check_feature_state (ML_FEATURE);
1907 :
1908 0 : if (!_ml_info_is_valid (list, ML_INFO_TYPE_INFORMATION_LIST)) {
1909 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1910 : "The parameter, 'list' is invalid. It should be a valid ml_information_list_h, which should be created by ml_information_list_create().");
1911 : }
1912 :
1913 0 : if (!length) {
1914 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1915 : "The parameter, 'length' is NULL. It should be a valid unsigned int*");
1916 : }
1917 :
1918 0 : _info_list = (ml_info_list_s *) list;
1919 0 : *length = g_slist_length (_info_list->info);
1920 :
1921 0 : return ML_ERROR_NONE;
1922 : }
1923 :
1924 : /**
1925 : * @brief Gets a ml-information in ml-information-list instance with given index.
1926 : */
1927 : int
1928 0 : ml_information_list_get (ml_information_list_h list, unsigned int index,
1929 : ml_information_h * information)
1930 : {
1931 : ml_info_list_s *_info_list;
1932 :
1933 0 : check_feature_state (ML_FEATURE);
1934 :
1935 0 : if (!_ml_info_is_valid (list, ML_INFO_TYPE_INFORMATION_LIST)) {
1936 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1937 : "The parameter, 'list' is NULL. It should be a valid ml_information_list_h, which should be created by ml_information_list_create().");
1938 : }
1939 :
1940 0 : if (!information) {
1941 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1942 : "The parameter, 'information' is NULL. It should be a valid ml_information_h*");
1943 : }
1944 :
1945 0 : _info_list = (ml_info_list_s *) list;
1946 0 : *information = g_slist_nth_data (_info_list->info, index);
1947 :
1948 0 : if (*information == NULL) {
1949 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1950 : "The parameter, 'index' is invalid. It should be less than the length of ml_information_list_h.");
1951 : }
1952 :
1953 0 : return ML_ERROR_NONE;
1954 : }
|