6e33ae7b23e5ee8d2c97ea596fe356fb3bf499ee
[babeltrace.git] / lib / value.c
1 /*
2 * Copyright (c) 2015-2018 Philippe Proulx <pproulx@efficios.com>
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 * SOFTWARE.
21 */
22
23 #define BT_LOG_TAG "VALUES"
24 #include <babeltrace/lib-logging-internal.h>
25
26 #include <stdlib.h>
27 #include <string.h>
28 #include <string.h>
29 #include <inttypes.h>
30 #include <babeltrace/compiler-internal.h>
31 #include <babeltrace/common-internal.h>
32 #include <babeltrace/value-const.h>
33 #include <babeltrace/value.h>
34 #include <babeltrace/compat/glib-internal.h>
35 #include <babeltrace/types.h>
36 #include <babeltrace/assert-pre-internal.h>
37 #include <babeltrace/value-internal.h>
38 #include <babeltrace/assert-internal.h>
39
40 #define BT_VALUE_TO_BOOL(_base) ((struct bt_value_bool *) (_base))
41 #define BT_VALUE_TO_INTEGER(_base) ((struct bt_value_integer *) (_base))
42 #define BT_VALUE_TO_REAL(_base) ((struct bt_value_real *) (_base))
43 #define BT_VALUE_TO_STRING(_base) ((struct bt_value_string *) (_base))
44 #define BT_VALUE_TO_ARRAY(_base) ((struct bt_value_array *) (_base))
45 #define BT_VALUE_TO_MAP(_base) ((struct bt_value_map *) (_base))
46
47 #define BT_ASSERT_PRE_VALUE_IS_TYPE(_value, _type) \
48 BT_ASSERT_PRE(((struct bt_value *) (_value))->type == (_type), \
49 "Value has the wrong type ID: expected-type=%s, " \
50 "%![value-]+v", bt_common_value_type_string(_type), \
51 (_value))
52
53 #define BT_ASSERT_PRE_VALUE_HOT(_value, _name) \
54 BT_ASSERT_PRE_HOT(((struct bt_value *) (_value)), (_name), \
55 ": %!+v", (_value))
56
57 #define BT_ASSERT_PRE_VALUE_INDEX_IN_BOUNDS(_index, _count) \
58 BT_ASSERT_PRE((_index) < (_count), \
59 "Index is out of bound: " \
60 "index=%" PRIu64 ", count=%u", (_index), (_count));
61
62 static
63 void bt_value_null_instance_release_func(struct bt_object *obj)
64 {
65 BT_LOGW("Releasing the null value singleton: addr=%p", obj);
66 }
67
68 static
69 struct bt_value bt_value_null_instance = {
70 .base = {
71 .is_shared = true,
72 .ref_count = 1,
73 .release_func = bt_value_null_instance_release_func,
74 .spec_release_func = NULL,
75 .parent_is_owner_listener_func = NULL,
76 .parent = NULL,
77 },
78 .type = BT_VALUE_TYPE_NULL,
79 .frozen = BT_TRUE,
80 };
81
82 struct bt_value *const bt_value_null = &bt_value_null_instance;
83
84 static
85 void bt_value_destroy(struct bt_object *obj);
86
87 static
88 void bt_value_string_destroy(struct bt_value *object)
89 {
90 g_string_free(BT_VALUE_TO_STRING(object)->gstr, TRUE);
91 BT_VALUE_TO_STRING(object)->gstr = NULL;
92 }
93
94 static
95 void bt_value_array_destroy(struct bt_value *object)
96 {
97 /*
98 * Pointer array's registered value destructor will take care
99 * of putting each contained object.
100 */
101 g_ptr_array_free(BT_VALUE_TO_ARRAY(object)->garray, TRUE);
102 BT_VALUE_TO_ARRAY(object)->garray = NULL;
103 }
104
105 static
106 void bt_value_map_destroy(struct bt_value *object)
107 {
108 /*
109 * Hash table's registered value destructor will take care of
110 * putting each contained object. Keys are GQuarks and cannot
111 * be destroyed anyway.
112 */
113 g_hash_table_destroy(BT_VALUE_TO_MAP(object)->ght);
114 BT_VALUE_TO_MAP(object)->ght = NULL;
115 }
116
117 static
118 void (* const destroy_funcs[])(struct bt_value *) = {
119 [BT_VALUE_TYPE_NULL] = NULL,
120 [BT_VALUE_TYPE_BOOL] = NULL,
121 [BT_VALUE_TYPE_INTEGER] = NULL,
122 [BT_VALUE_TYPE_REAL] = NULL,
123 [BT_VALUE_TYPE_STRING] = bt_value_string_destroy,
124 [BT_VALUE_TYPE_ARRAY] = bt_value_array_destroy,
125 [BT_VALUE_TYPE_MAP] = bt_value_map_destroy,
126 };
127
128 static
129 struct bt_value *bt_value_null_copy(const struct bt_value *null_obj)
130 {
131 return (void *) bt_value_null;
132 }
133
134 static
135 struct bt_value *bt_value_bool_copy(const struct bt_value *bool_obj)
136 {
137 return bt_value_bool_create_init(
138 BT_VALUE_TO_BOOL(bool_obj)->value);
139 }
140
141 static
142 struct bt_value *bt_value_integer_copy(
143 const struct bt_value *integer_obj)
144 {
145 return bt_value_integer_create_init(
146 BT_VALUE_TO_INTEGER(integer_obj)->value);
147 }
148
149 static
150 struct bt_value *bt_value_real_copy(const struct bt_value *real_obj)
151 {
152 return bt_value_real_create_init(
153 BT_VALUE_TO_REAL(real_obj)->value);
154 }
155
156 static
157 struct bt_value *bt_value_string_copy(const struct bt_value *string_obj)
158 {
159 return bt_value_string_create_init(
160 BT_VALUE_TO_STRING(string_obj)->gstr->str);
161 }
162
163 static
164 struct bt_value *bt_value_array_copy(const struct bt_value *array_obj)
165 {
166 int i;
167 int ret;
168 struct bt_value *copy_obj;
169 struct bt_value_array *typed_array_obj;
170
171 BT_LOGD("Copying array value: addr=%p", array_obj);
172 typed_array_obj = BT_VALUE_TO_ARRAY(array_obj);
173 copy_obj = bt_value_array_create();
174 if (!copy_obj) {
175 BT_LOGE_STR("Cannot create empty array value.");
176 goto end;
177 }
178
179 for (i = 0; i < typed_array_obj->garray->len; ++i) {
180 struct bt_value *element_obj_copy = NULL;
181 const struct bt_value *element_obj =
182 bt_value_array_borrow_element_by_index_const(
183 array_obj, i);
184
185 BT_ASSERT(element_obj);
186 BT_LOGD("Copying array value's element: element-addr=%p, "
187 "index=%d", element_obj, i);
188 ret = bt_value_copy(element_obj, &element_obj_copy);
189 if (ret) {
190 BT_LOGE("Cannot copy array value's element: "
191 "array-addr=%p, index=%d",
192 array_obj, i);
193 BT_OBJECT_PUT_REF_AND_RESET(copy_obj);
194 goto end;
195 }
196
197 BT_ASSERT(element_obj_copy);
198 ret = bt_value_array_append_element(copy_obj,
199 (void *) element_obj_copy);
200 BT_OBJECT_PUT_REF_AND_RESET(element_obj_copy);
201 if (ret) {
202 BT_LOGE("Cannot append to array value: addr=%p",
203 array_obj);
204 BT_OBJECT_PUT_REF_AND_RESET(copy_obj);
205 goto end;
206 }
207 }
208
209 BT_LOGD("Copied array value: original-addr=%p, copy-addr=%p",
210 array_obj, copy_obj);
211
212 end:
213 return copy_obj;
214 }
215
216 static
217 struct bt_value *bt_value_map_copy(const struct bt_value *map_obj)
218 {
219 int ret;
220 GHashTableIter iter;
221 gpointer key, element_obj;
222 struct bt_value *copy_obj;
223 struct bt_value *element_obj_copy = NULL;
224 struct bt_value_map *typed_map_obj;
225
226 BT_LOGD("Copying map value: addr=%p", map_obj);
227 typed_map_obj = BT_VALUE_TO_MAP(map_obj);
228 copy_obj = bt_value_map_create();
229 if (!copy_obj) {
230 goto end;
231 }
232
233 g_hash_table_iter_init(&iter, typed_map_obj->ght);
234
235 while (g_hash_table_iter_next(&iter, &key, &element_obj)) {
236 const char *key_str = g_quark_to_string(GPOINTER_TO_UINT(key));
237
238 BT_ASSERT(key_str);
239 BT_LOGD("Copying map value's element: element-addr=%p, "
240 "key=\"%s\"", element_obj, key_str);
241 ret = bt_value_copy(element_obj, &element_obj_copy);
242 if (ret) {
243 BT_LOGE("Cannot copy map value's element: "
244 "map-addr=%p, key=\"%s\"",
245 map_obj, key_str);
246 BT_OBJECT_PUT_REF_AND_RESET(copy_obj);
247 goto end;
248 }
249
250 BT_ASSERT(element_obj_copy);
251 ret = bt_value_map_insert_entry(copy_obj, key_str,
252 (void *) element_obj_copy);
253 BT_OBJECT_PUT_REF_AND_RESET(element_obj_copy);
254 if (ret) {
255 BT_LOGE("Cannot insert into map value: addr=%p, key=\"%s\"",
256 map_obj, key_str);
257 BT_OBJECT_PUT_REF_AND_RESET(copy_obj);
258 goto end;
259 }
260 }
261
262 BT_LOGD("Copied map value: addr=%p", map_obj);
263
264 end:
265 return copy_obj;
266 }
267
268 static
269 struct bt_value *(* const copy_funcs[])(const struct bt_value *) = {
270 [BT_VALUE_TYPE_NULL] = bt_value_null_copy,
271 [BT_VALUE_TYPE_BOOL] = bt_value_bool_copy,
272 [BT_VALUE_TYPE_INTEGER] = bt_value_integer_copy,
273 [BT_VALUE_TYPE_REAL] = bt_value_real_copy,
274 [BT_VALUE_TYPE_STRING] = bt_value_string_copy,
275 [BT_VALUE_TYPE_ARRAY] = bt_value_array_copy,
276 [BT_VALUE_TYPE_MAP] = bt_value_map_copy,
277 };
278
279 static
280 bt_bool bt_value_null_compare(const struct bt_value *object_a,
281 const struct bt_value *object_b)
282 {
283 /*
284 * Always BT_TRUE since bt_value_compare() already checks if both
285 * object_a and object_b have the same type, and in the case of
286 * null value objects, they're always the same if it is so.
287 */
288 return BT_TRUE;
289 }
290
291 static
292 bt_bool bt_value_bool_compare(const struct bt_value *object_a,
293 const struct bt_value *object_b)
294 {
295 if (BT_VALUE_TO_BOOL(object_a)->value !=
296 BT_VALUE_TO_BOOL(object_b)->value) {
297 BT_LOGV("Boolean value objects are different: "
298 "bool-a-val=%d, bool-b-val=%d",
299 BT_VALUE_TO_BOOL(object_a)->value,
300 BT_VALUE_TO_BOOL(object_b)->value);
301 return BT_FALSE;
302 }
303
304 return BT_TRUE;
305 }
306
307 static
308 bt_bool bt_value_integer_compare(const struct bt_value *object_a,
309 const struct bt_value *object_b)
310 {
311 if (BT_VALUE_TO_INTEGER(object_a)->value !=
312 BT_VALUE_TO_INTEGER(object_b)->value) {
313 BT_LOGV("Integer value objects are different: "
314 "int-a-val=%" PRId64 ", int-b-val=%" PRId64,
315 BT_VALUE_TO_INTEGER(object_a)->value,
316 BT_VALUE_TO_INTEGER(object_b)->value);
317 return BT_FALSE;
318 }
319
320 return BT_TRUE;
321 }
322
323 static
324 bt_bool bt_value_real_compare(const struct bt_value *object_a,
325 const struct bt_value *object_b)
326 {
327 if (BT_VALUE_TO_REAL(object_a)->value !=
328 BT_VALUE_TO_REAL(object_b)->value) {
329 BT_LOGV("Real number value objects are different: "
330 "real-a-val=%f, real-b-val=%f",
331 BT_VALUE_TO_REAL(object_a)->value,
332 BT_VALUE_TO_REAL(object_b)->value);
333 return BT_FALSE;
334 }
335
336 return BT_TRUE;
337 }
338
339 static
340 bt_bool bt_value_string_compare(const struct bt_value *object_a,
341 const struct bt_value *object_b)
342 {
343 if (strcmp(BT_VALUE_TO_STRING(object_a)->gstr->str,
344 BT_VALUE_TO_STRING(object_b)->gstr->str) != 0) {
345 BT_LOGV("String value objects are different: "
346 "string-a-val=\"%s\", string-b-val=\"%s\"",
347 BT_VALUE_TO_STRING(object_a)->gstr->str,
348 BT_VALUE_TO_STRING(object_b)->gstr->str);
349 return BT_FALSE;
350 }
351
352 return BT_TRUE;
353 }
354
355 static
356 bt_bool bt_value_array_compare(const struct bt_value *object_a,
357 const struct bt_value *object_b)
358 {
359 int i;
360 bt_bool ret = BT_TRUE;
361 const struct bt_value_array *array_obj_a =
362 BT_VALUE_TO_ARRAY(object_a);
363
364 if (bt_value_array_get_size(object_a) !=
365 bt_value_array_get_size(object_b)) {
366 BT_LOGV("Array values are different: size mismatch "
367 "value-a-addr=%p, value-b-addr=%p, "
368 "value-a-size=%" PRId64 ", value-b-size=%" PRId64,
369 object_a, object_b,
370 bt_value_array_get_size(object_a),
371 bt_value_array_get_size(object_b));
372 ret = BT_FALSE;
373 goto end;
374 }
375
376 for (i = 0; i < array_obj_a->garray->len; ++i) {
377 const struct bt_value *element_obj_a;
378 const struct bt_value *element_obj_b;
379
380 element_obj_a = bt_value_array_borrow_element_by_index_const(
381 object_a, i);
382 element_obj_b = bt_value_array_borrow_element_by_index_const(
383 object_b, i);
384
385 if (!bt_value_compare(element_obj_a, element_obj_b)) {
386 BT_LOGV("Array values's elements are different: "
387 "value-a-addr=%p, value-b-addr=%p, index=%d",
388 element_obj_a, element_obj_b, i);
389 ret = BT_FALSE;
390 goto end;
391 }
392 }
393
394 end:
395 return ret;
396 }
397
398 static
399 bt_bool bt_value_map_compare(const struct bt_value *object_a,
400 const struct bt_value *object_b)
401 {
402 bt_bool ret = BT_TRUE;
403 GHashTableIter iter;
404 gpointer key, element_obj_a;
405 const struct bt_value_map *map_obj_a = BT_VALUE_TO_MAP(object_a);
406
407 if (bt_value_map_get_size(object_a) !=
408 bt_value_map_get_size(object_b)) {
409 BT_LOGV("Map values are different: size mismatch "
410 "value-a-addr=%p, value-b-addr=%p, "
411 "value-a-size=%" PRId64 ", value-b-size=%" PRId64,
412 object_a, object_b,
413 bt_value_map_get_size(object_a),
414 bt_value_map_get_size(object_b));
415 ret = BT_FALSE;
416 goto end;
417 }
418
419 g_hash_table_iter_init(&iter, map_obj_a->ght);
420
421 while (g_hash_table_iter_next(&iter, &key, &element_obj_a)) {
422 const struct bt_value *element_obj_b;
423 const char *key_str = g_quark_to_string(GPOINTER_TO_UINT(key));
424
425 element_obj_b = bt_value_map_borrow_entry_value_const(object_b,
426 key_str);
427
428 if (!bt_value_compare(element_obj_a, element_obj_b)) {
429 BT_LOGV("Map values's elements are different: "
430 "value-a-addr=%p, value-b-addr=%p, key=\"%s\"",
431 element_obj_a, element_obj_b, key_str);
432 ret = BT_FALSE;
433 goto end;
434 }
435 }
436
437 end:
438 return ret;
439 }
440
441 static
442 bt_bool (* const compare_funcs[])(const struct bt_value *,
443 const struct bt_value *) = {
444 [BT_VALUE_TYPE_NULL] = bt_value_null_compare,
445 [BT_VALUE_TYPE_BOOL] = bt_value_bool_compare,
446 [BT_VALUE_TYPE_INTEGER] = bt_value_integer_compare,
447 [BT_VALUE_TYPE_REAL] = bt_value_real_compare,
448 [BT_VALUE_TYPE_STRING] = bt_value_string_compare,
449 [BT_VALUE_TYPE_ARRAY] = bt_value_array_compare,
450 [BT_VALUE_TYPE_MAP] = bt_value_map_compare,
451 };
452
453 static
454 void bt_value_null_freeze(struct bt_value *object)
455 {
456 }
457
458 static
459 void bt_value_generic_freeze(struct bt_value *object)
460 {
461 object->frozen = BT_TRUE;
462 }
463
464 static
465 void bt_value_array_freeze(struct bt_value *object)
466 {
467 int i;
468 struct bt_value_array *typed_array_obj =
469 BT_VALUE_TO_ARRAY(object);
470
471 for (i = 0; i < typed_array_obj->garray->len; ++i) {
472 bt_value_freeze(g_ptr_array_index(typed_array_obj->garray, i));
473 }
474
475 bt_value_generic_freeze(object);
476 }
477
478 static
479 void bt_value_map_freeze(struct bt_value *object)
480 {
481 GHashTableIter iter;
482 gpointer key, element_obj;
483 const struct bt_value_map *map_obj = BT_VALUE_TO_MAP(object);
484
485 g_hash_table_iter_init(&iter, map_obj->ght);
486
487 while (g_hash_table_iter_next(&iter, &key, &element_obj)) {
488 bt_value_freeze(element_obj);
489 }
490
491 bt_value_generic_freeze(object);
492 }
493
494 static
495 void (* const freeze_funcs[])(struct bt_value *) = {
496 [BT_VALUE_TYPE_NULL] = bt_value_null_freeze,
497 [BT_VALUE_TYPE_BOOL] = bt_value_generic_freeze,
498 [BT_VALUE_TYPE_INTEGER] = bt_value_generic_freeze,
499 [BT_VALUE_TYPE_REAL] = bt_value_generic_freeze,
500 [BT_VALUE_TYPE_STRING] = bt_value_generic_freeze,
501 [BT_VALUE_TYPE_ARRAY] = bt_value_array_freeze,
502 [BT_VALUE_TYPE_MAP] = bt_value_map_freeze,
503 };
504
505 static
506 void bt_value_destroy(struct bt_object *obj)
507 {
508 struct bt_value *value;
509
510 value = container_of(obj, struct bt_value, base);
511 BT_LOGD("Destroying value: addr=%p", value);
512
513 if (bt_value_is_null(value)) {
514 BT_LOGD_STR("Not destroying the null value singleton.");
515 return;
516 }
517
518 if (destroy_funcs[value->type]) {
519 destroy_funcs[value->type](value);
520 }
521
522 g_free(value);
523 }
524
525 BT_HIDDEN
526 enum bt_value_status _bt_value_freeze(const struct bt_value *c_object)
527 {
528 const struct bt_value *object = (void *) c_object;
529 enum bt_value_status ret = BT_VALUE_STATUS_OK;
530
531 BT_ASSERT(object);
532
533 if (object->frozen) {
534 goto end;
535 }
536
537 BT_LOGD("Freezing value: addr=%p", object);
538 freeze_funcs[object->type]((void *) object);
539
540 end:
541 return ret;
542 }
543
544 enum bt_value_type bt_value_get_type(const struct bt_value *object)
545 {
546 BT_ASSERT_PRE_NON_NULL(object, "Value object");
547 return object->type;
548 }
549
550 static
551 struct bt_value bt_value_create_base(enum bt_value_type type)
552 {
553 struct bt_value value;
554
555 value.type = type;
556 value.frozen = BT_FALSE;
557 bt_object_init_shared(&value.base, bt_value_destroy);
558 return value;
559 }
560
561 struct bt_value *bt_value_bool_create_init(bt_bool val)
562 {
563 struct bt_value_bool *bool_obj;
564
565 BT_LOGD("Creating boolean value object: val=%d", val);
566 bool_obj = g_new0(struct bt_value_bool, 1);
567 if (!bool_obj) {
568 BT_LOGE_STR("Failed to allocate one boolean value object.");
569 goto end;
570 }
571
572 bool_obj->base = bt_value_create_base(BT_VALUE_TYPE_BOOL);
573 bool_obj->value = val;
574 BT_LOGD("Created boolean value object: addr=%p", bool_obj);
575
576 end:
577 return (void *) bool_obj;
578 }
579
580 struct bt_value *bt_value_bool_create(void)
581 {
582 return bt_value_bool_create_init(BT_FALSE);
583 }
584
585 struct bt_value *bt_value_integer_create_init(int64_t val)
586 {
587 struct bt_value_integer *integer_obj;
588
589 BT_LOGD("Creating integer value object: val=%" PRId64, val);
590 integer_obj = g_new0(struct bt_value_integer, 1);
591 if (!integer_obj) {
592 BT_LOGE_STR("Failed to allocate one integer value object.");
593 goto end;
594 }
595
596 integer_obj->base = bt_value_create_base(BT_VALUE_TYPE_INTEGER);
597 integer_obj->value = val;
598 BT_LOGD("Created integer value object: addr=%p",
599 integer_obj);
600
601 end:
602 return (void *) integer_obj;
603 }
604
605 struct bt_value *bt_value_integer_create(void)
606 {
607 return bt_value_integer_create_init(0);
608 }
609
610 struct bt_value *bt_value_real_create_init(double val)
611 {
612 struct bt_value_real *real_obj;
613
614 BT_LOGD("Creating real number value object: val=%f", val);
615 real_obj = g_new0(struct bt_value_real, 1);
616 if (!real_obj) {
617 BT_LOGE_STR("Failed to allocate one real number value object.");
618 goto end;
619 }
620
621 real_obj->base = bt_value_create_base(BT_VALUE_TYPE_REAL);
622 real_obj->value = val;
623 BT_LOGD("Created real number value object: addr=%p",
624 real_obj);
625
626 end:
627 return (void *) real_obj;
628 }
629
630 struct bt_value *bt_value_real_create(void)
631 {
632 return bt_value_real_create_init(0.);
633 }
634
635 struct bt_value *bt_value_string_create_init(const char *val)
636 {
637 struct bt_value_string *string_obj = NULL;
638
639 if (!val) {
640 BT_LOGW_STR("Invalid parameter: value is NULL.");
641 goto end;
642 }
643
644 BT_LOGD("Creating string value object: val-len=%zu", strlen(val));
645 string_obj = g_new0(struct bt_value_string, 1);
646 if (!string_obj) {
647 BT_LOGE_STR("Failed to allocate one string object.");
648 goto end;
649 }
650
651 string_obj->base = bt_value_create_base(BT_VALUE_TYPE_STRING);
652 string_obj->gstr = g_string_new(val);
653 if (!string_obj->gstr) {
654 BT_LOGE_STR("Failed to allocate a GString.");
655 g_free(string_obj);
656 string_obj = NULL;
657 goto end;
658 }
659
660 BT_LOGD("Created string value object: addr=%p",
661 string_obj);
662
663 end:
664 return (void *) string_obj;
665 }
666
667 struct bt_value *bt_value_string_create(void)
668 {
669 return bt_value_string_create_init("");
670 }
671
672 struct bt_value *bt_value_array_create(void)
673 {
674 struct bt_value_array *array_obj;
675
676 BT_LOGD_STR("Creating empty array value object.");
677 array_obj = g_new0(struct bt_value_array, 1);
678 if (!array_obj) {
679 BT_LOGE_STR("Failed to allocate one array object.");
680 goto end;
681 }
682
683 array_obj->base = bt_value_create_base(BT_VALUE_TYPE_ARRAY);
684 array_obj->garray = bt_g_ptr_array_new_full(0,
685 (GDestroyNotify) bt_object_put_ref);
686 if (!array_obj->garray) {
687 BT_LOGE_STR("Failed to allocate a GPtrArray.");
688 g_free(array_obj);
689 array_obj = NULL;
690 goto end;
691 }
692
693 BT_LOGD("Created array value object: addr=%p",
694 array_obj);
695
696 end:
697 return (void *) array_obj;
698 }
699
700 struct bt_value *bt_value_map_create(void)
701 {
702 struct bt_value_map *map_obj;
703
704 BT_LOGD_STR("Creating empty map value object.");
705 map_obj = g_new0(struct bt_value_map, 1);
706 if (!map_obj) {
707 BT_LOGE_STR("Failed to allocate one map object.");
708 goto end;
709 }
710
711 map_obj->base = bt_value_create_base(BT_VALUE_TYPE_MAP);
712 map_obj->ght = g_hash_table_new_full(g_direct_hash, g_direct_equal,
713 NULL, (GDestroyNotify) bt_object_put_ref);
714 if (!map_obj->ght) {
715 BT_LOGE_STR("Failed to allocate a GHashTable.");
716 g_free(map_obj);
717 map_obj = NULL;
718 goto end;
719 }
720
721 BT_LOGD("Created map value object: addr=%p",
722 map_obj);
723
724 end:
725 return (void *) map_obj;
726 }
727
728 bt_bool bt_value_bool_get(const struct bt_value *bool_obj)
729 {
730 BT_ASSERT_PRE_NON_NULL(bool_obj, "Value object");
731 BT_ASSERT_PRE_VALUE_IS_TYPE(bool_obj, BT_VALUE_TYPE_BOOL);
732 return BT_VALUE_TO_BOOL(bool_obj)->value;
733 }
734
735 void bt_value_bool_set(struct bt_value *bool_obj, bt_bool val)
736 {
737 BT_ASSERT_PRE_NON_NULL(bool_obj, "Value object");
738 BT_ASSERT_PRE_VALUE_IS_TYPE(bool_obj, BT_VALUE_TYPE_BOOL);
739 BT_ASSERT_PRE_VALUE_HOT(bool_obj, "Value object");
740 BT_VALUE_TO_BOOL(bool_obj)->value = val;
741 BT_LOGV("Set boolean value's raw value: value-addr=%p, value=%d",
742 bool_obj, val);
743 }
744
745 int64_t bt_value_integer_get(const struct bt_value *integer_obj)
746 {
747 BT_ASSERT_PRE_NON_NULL(integer_obj, "Value object");
748 BT_ASSERT_PRE_VALUE_IS_TYPE(integer_obj, BT_VALUE_TYPE_INTEGER);
749 return BT_VALUE_TO_INTEGER(integer_obj)->value;
750 }
751
752 void bt_value_integer_set(struct bt_value *integer_obj,
753 int64_t val)
754 {
755 BT_ASSERT_PRE_NON_NULL(integer_obj, "Value object");
756 BT_ASSERT_PRE_VALUE_IS_TYPE(integer_obj, BT_VALUE_TYPE_INTEGER);
757 BT_ASSERT_PRE_VALUE_HOT(integer_obj, "Value object");
758 BT_VALUE_TO_INTEGER(integer_obj)->value = val;
759 BT_LOGV("Set integer value's raw value: value-addr=%p, value=%" PRId64,
760 integer_obj, val);
761 }
762
763 double bt_value_real_get(const struct bt_value *real_obj)
764 {
765 BT_ASSERT_PRE_NON_NULL(real_obj, "Value object");
766 BT_ASSERT_PRE_VALUE_IS_TYPE(real_obj, BT_VALUE_TYPE_REAL);
767 return BT_VALUE_TO_REAL(real_obj)->value;
768 }
769
770 void bt_value_real_set(struct bt_value *real_obj, double val)
771 {
772 BT_ASSERT_PRE_NON_NULL(real_obj, "Value object");
773 BT_ASSERT_PRE_VALUE_IS_TYPE(real_obj, BT_VALUE_TYPE_REAL);
774 BT_ASSERT_PRE_VALUE_HOT(real_obj, "Value object");
775 BT_VALUE_TO_REAL(real_obj)->value = val;
776 BT_LOGV("Set real number value's raw value: value-addr=%p, value=%f",
777 real_obj, val);
778 }
779
780 const char *bt_value_string_get(const struct bt_value *string_obj)
781 {
782 BT_ASSERT_PRE_NON_NULL(string_obj, "Value object");
783 BT_ASSERT_PRE_VALUE_IS_TYPE(string_obj, BT_VALUE_TYPE_STRING);
784 return BT_VALUE_TO_STRING(string_obj)->gstr->str;
785 }
786
787 enum bt_value_status bt_value_string_set(
788 struct bt_value *string_obj, const char *val)
789 {
790 BT_ASSERT_PRE_NON_NULL(string_obj, "Value object");
791 BT_ASSERT_PRE_VALUE_IS_TYPE(string_obj, BT_VALUE_TYPE_STRING);
792 BT_ASSERT_PRE_VALUE_HOT(string_obj, "Value object");
793 g_string_assign(BT_VALUE_TO_STRING(string_obj)->gstr, val);
794 BT_LOGV("Set string value's raw value: value-addr=%p, raw-value-addr=%p",
795 string_obj, val);
796 return BT_VALUE_STATUS_OK;
797 }
798
799 uint64_t bt_value_array_get_size(const struct bt_value *array_obj)
800 {
801 BT_ASSERT_PRE_NON_NULL(array_obj, "Value object");
802 BT_ASSERT_PRE_VALUE_IS_TYPE(array_obj, BT_VALUE_TYPE_ARRAY);
803 return (uint64_t) BT_VALUE_TO_ARRAY(array_obj)->garray->len;
804 }
805
806 struct bt_value *bt_value_array_borrow_element_by_index(
807 struct bt_value *array_obj, uint64_t index)
808 {
809 struct bt_value_array *typed_array_obj =
810 BT_VALUE_TO_ARRAY(array_obj);
811
812 BT_ASSERT_PRE_NON_NULL(array_obj, "Value object");
813 BT_ASSERT_PRE_VALUE_IS_TYPE(array_obj, BT_VALUE_TYPE_ARRAY);
814 BT_ASSERT_PRE_VALUE_INDEX_IN_BOUNDS(index,
815 typed_array_obj->garray->len);
816 return g_ptr_array_index(typed_array_obj->garray, index);
817 }
818
819 const struct bt_value *bt_value_array_borrow_element_by_index_const(
820 const struct bt_value *array_obj,
821 uint64_t index)
822 {
823 return bt_value_array_borrow_element_by_index(
824 (void *) array_obj, index);
825 }
826
827 enum bt_value_status bt_value_array_append_element(
828 struct bt_value *array_obj,
829 struct bt_value *element_obj)
830 {
831 struct bt_value_array *typed_array_obj =
832 BT_VALUE_TO_ARRAY(array_obj);
833
834 BT_ASSERT_PRE_NON_NULL(array_obj, "Array value object");
835 BT_ASSERT_PRE_NON_NULL(element_obj, "Element value object");
836 BT_ASSERT_PRE_VALUE_IS_TYPE(array_obj, BT_VALUE_TYPE_ARRAY);
837 BT_ASSERT_PRE_VALUE_HOT(array_obj, "Array value object");
838 g_ptr_array_add(typed_array_obj->garray, element_obj);
839 bt_object_get_ref(element_obj);
840 BT_LOGV("Appended element to array value: array-value-addr=%p, "
841 "element-value-addr=%p, new-size=%u",
842 array_obj, element_obj, typed_array_obj->garray->len);
843 return BT_VALUE_STATUS_OK;
844 }
845
846 enum bt_value_status bt_value_array_append_bool_element(
847 struct bt_value *array_obj, bt_bool val)
848 {
849 enum bt_value_status ret;
850 struct bt_value *bool_obj = NULL;
851
852 bool_obj = bt_value_bool_create_init(val);
853 ret = bt_value_array_append_element(array_obj,
854 (void *) bool_obj);
855 bt_object_put_ref(bool_obj);
856 return ret;
857 }
858
859 enum bt_value_status bt_value_array_append_integer_element(
860 struct bt_value *array_obj, int64_t val)
861 {
862 enum bt_value_status ret;
863 struct bt_value *integer_obj = NULL;
864
865 integer_obj = bt_value_integer_create_init(val);
866 ret = bt_value_array_append_element(array_obj,
867 (void *) integer_obj);
868 bt_object_put_ref(integer_obj);
869 return ret;
870 }
871
872 enum bt_value_status bt_value_array_append_real_element(
873 struct bt_value *array_obj, double val)
874 {
875 enum bt_value_status ret;
876 struct bt_value *real_obj = NULL;
877
878 real_obj = bt_value_real_create_init(val);
879 ret = bt_value_array_append_element(array_obj,
880 (void *) real_obj);
881 bt_object_put_ref(real_obj);
882 return ret;
883 }
884
885 enum bt_value_status bt_value_array_append_string_element(
886 struct bt_value *array_obj, const char *val)
887 {
888 enum bt_value_status ret;
889 struct bt_value *string_obj = NULL;
890
891 string_obj = bt_value_string_create_init(val);
892 ret = bt_value_array_append_element(array_obj,
893 (void *) string_obj);
894 bt_object_put_ref(string_obj);
895 return ret;
896 }
897
898 enum bt_value_status bt_value_array_append_empty_array_element(
899 struct bt_value *array_obj)
900 {
901 enum bt_value_status ret;
902 struct bt_value *empty_array_obj = NULL;
903
904 empty_array_obj = bt_value_array_create();
905 ret = bt_value_array_append_element(array_obj,
906 (void *) empty_array_obj);
907 bt_object_put_ref(empty_array_obj);
908 return ret;
909 }
910
911 enum bt_value_status bt_value_array_append_empty_map_element(
912 struct bt_value *array_obj)
913 {
914 enum bt_value_status ret;
915 struct bt_value *map_obj = NULL;
916
917 map_obj = bt_value_map_create();
918 ret = bt_value_array_append_element(array_obj,
919 (void *) map_obj);
920 bt_object_put_ref(map_obj);
921 return ret;
922 }
923
924 enum bt_value_status bt_value_array_set_element_by_index(
925 struct bt_value *array_obj, uint64_t index,
926 struct bt_value *element_obj)
927 {
928 struct bt_value_array *typed_array_obj =
929 BT_VALUE_TO_ARRAY(array_obj);
930
931 BT_ASSERT_PRE_NON_NULL(array_obj, "Array value object");
932 BT_ASSERT_PRE_NON_NULL(element_obj, "Element value object");
933 BT_ASSERT_PRE_VALUE_IS_TYPE(array_obj, BT_VALUE_TYPE_ARRAY);
934 BT_ASSERT_PRE_VALUE_HOT(array_obj, "Array value object");
935 BT_ASSERT_PRE_VALUE_INDEX_IN_BOUNDS(index,
936 typed_array_obj->garray->len);
937 bt_object_put_ref(g_ptr_array_index(typed_array_obj->garray, index));
938 g_ptr_array_index(typed_array_obj->garray, index) = element_obj;
939 bt_object_get_ref(element_obj);
940 BT_LOGV("Set array value's element: array-value-addr=%p, "
941 "index=%" PRIu64 ", element-value-addr=%p",
942 array_obj, index, element_obj);
943 return BT_VALUE_STATUS_OK;
944 }
945
946 uint64_t bt_value_map_get_size(const struct bt_value *map_obj)
947 {
948 BT_ASSERT_PRE_NON_NULL(map_obj, "Value object");
949 BT_ASSERT_PRE_VALUE_IS_TYPE(map_obj, BT_VALUE_TYPE_MAP);
950 return (uint64_t) g_hash_table_size(BT_VALUE_TO_MAP(map_obj)->ght);
951 }
952
953 struct bt_value *bt_value_map_borrow_entry_value(struct bt_value *map_obj,
954 const char *key)
955 {
956 BT_ASSERT_PRE_NON_NULL(map_obj, "Value object");
957 BT_ASSERT_PRE_NON_NULL(key, "Key");
958 BT_ASSERT_PRE_VALUE_IS_TYPE(map_obj, BT_VALUE_TYPE_MAP);
959 return g_hash_table_lookup(BT_VALUE_TO_MAP(map_obj)->ght,
960 GUINT_TO_POINTER(g_quark_from_string(key)));
961 }
962
963 const struct bt_value *bt_value_map_borrow_entry_value_const(
964 const struct bt_value *map_obj, const char *key)
965 {
966 return bt_value_map_borrow_entry_value((void *) map_obj, key);
967 }
968
969 bt_bool bt_value_map_has_entry(const struct bt_value *map_obj, const char *key)
970 {
971 BT_ASSERT_PRE_NON_NULL(map_obj, "Value object");
972 BT_ASSERT_PRE_NON_NULL(key, "Key");
973 BT_ASSERT_PRE_VALUE_IS_TYPE(map_obj, BT_VALUE_TYPE_MAP);
974 return bt_g_hash_table_contains(BT_VALUE_TO_MAP(map_obj)->ght,
975 GUINT_TO_POINTER(g_quark_from_string(key)));
976 }
977
978 enum bt_value_status bt_value_map_insert_entry(
979 struct bt_value *map_obj,
980 const char *key, struct bt_value *element_obj)
981 {
982 BT_ASSERT_PRE_NON_NULL(map_obj, "Map value object");
983 BT_ASSERT_PRE_NON_NULL(key, "Key");
984 BT_ASSERT_PRE_NON_NULL(element_obj, "Element value object");
985 BT_ASSERT_PRE_VALUE_IS_TYPE(map_obj, BT_VALUE_TYPE_MAP);
986 BT_ASSERT_PRE_VALUE_HOT(map_obj, "Map value object");
987 g_hash_table_insert(BT_VALUE_TO_MAP(map_obj)->ght,
988 GUINT_TO_POINTER(g_quark_from_string(key)), element_obj);
989 bt_object_get_ref(element_obj);
990 BT_LOGV("Inserted value into map value: map-value-addr=%p, "
991 "key=\"%s\", element-value-addr=%p",
992 map_obj, key, element_obj);
993 return BT_VALUE_STATUS_OK;
994 }
995
996 enum bt_value_status bt_value_map_insert_bool_entry(
997 struct bt_value *map_obj, const char *key, bt_bool val)
998 {
999 enum bt_value_status ret;
1000 struct bt_value *bool_obj = NULL;
1001
1002 bool_obj = bt_value_bool_create_init(val);
1003 ret = bt_value_map_insert_entry(map_obj, key,
1004 (void *) bool_obj);
1005 bt_object_put_ref(bool_obj);
1006 return ret;
1007 }
1008
1009 enum bt_value_status bt_value_map_insert_integer_entry(
1010 struct bt_value *map_obj, const char *key, int64_t val)
1011 {
1012 enum bt_value_status ret;
1013 struct bt_value *integer_obj = NULL;
1014
1015 integer_obj = bt_value_integer_create_init(val);
1016 ret = bt_value_map_insert_entry(map_obj, key,
1017 (void *) integer_obj);
1018 bt_object_put_ref(integer_obj);
1019 return ret;
1020 }
1021
1022 enum bt_value_status bt_value_map_insert_real_entry(
1023 struct bt_value *map_obj, const char *key, double val)
1024 {
1025 enum bt_value_status ret;
1026 struct bt_value *real_obj = NULL;
1027
1028 real_obj = bt_value_real_create_init(val);
1029 ret = bt_value_map_insert_entry(map_obj, key,
1030 (void *) real_obj);
1031 bt_object_put_ref(real_obj);
1032 return ret;
1033 }
1034
1035 enum bt_value_status bt_value_map_insert_string_entry(
1036 struct bt_value *map_obj, const char *key,
1037 const char *val)
1038 {
1039 enum bt_value_status ret;
1040 struct bt_value *string_obj = NULL;
1041
1042 string_obj = bt_value_string_create_init(val);
1043 ret = bt_value_map_insert_entry(map_obj, key,
1044 (void *) string_obj);
1045 bt_object_put_ref(string_obj);
1046 return ret;
1047 }
1048
1049 enum bt_value_status bt_value_map_insert_empty_array_entry(
1050 struct bt_value *map_obj, const char *key)
1051 {
1052 enum bt_value_status ret;
1053 struct bt_value *array_obj = NULL;
1054
1055 array_obj = bt_value_array_create();
1056 ret = bt_value_map_insert_entry(map_obj, key,
1057 (void *) array_obj);
1058 bt_object_put_ref(array_obj);
1059 return ret;
1060 }
1061
1062 enum bt_value_status bt_value_map_insert_empty_map_entry(
1063 struct bt_value *map_obj, const char *key)
1064 {
1065 enum bt_value_status ret;
1066 struct bt_value *empty_map_obj = NULL;
1067
1068 empty_map_obj = bt_value_map_create();
1069 ret = bt_value_map_insert_entry(map_obj, key,
1070 (void *) empty_map_obj);
1071 bt_object_put_ref(empty_map_obj);
1072 return ret;
1073 }
1074
1075 enum bt_value_status bt_value_map_foreach_entry(struct bt_value *map_obj,
1076 bt_value_map_foreach_entry_func func, void *data)
1077 {
1078 enum bt_value_status ret = BT_VALUE_STATUS_OK;
1079 gpointer key, element_obj;
1080 GHashTableIter iter;
1081 struct bt_value_map *typed_map_obj = BT_VALUE_TO_MAP(map_obj);
1082
1083 BT_ASSERT_PRE_NON_NULL(map_obj, "Value object");
1084 BT_ASSERT_PRE_NON_NULL(func, "Callback");
1085 BT_ASSERT_PRE_VALUE_IS_TYPE(map_obj, BT_VALUE_TYPE_MAP);
1086 g_hash_table_iter_init(&iter, typed_map_obj->ght);
1087
1088 while (g_hash_table_iter_next(&iter, &key, &element_obj)) {
1089 const char *key_str = g_quark_to_string(GPOINTER_TO_UINT(key));
1090
1091 if (!func(key_str, element_obj, data)) {
1092 BT_LOGV("User canceled the loop: key=\"%s\", "
1093 "value-addr=%p, data=%p",
1094 key_str, element_obj, data);
1095 ret = BT_VALUE_STATUS_CANCELED;
1096 break;
1097 }
1098 }
1099
1100 return ret;
1101 }
1102
1103 enum bt_value_status bt_value_map_foreach_entry_const(
1104 const struct bt_value *map_obj,
1105 bt_value_map_foreach_entry_const_func func, void *data)
1106 {
1107 return bt_value_map_foreach_entry((void *) map_obj,
1108 (bt_value_map_foreach_entry_func) func, data);
1109 }
1110
1111 struct extend_map_element_data {
1112 struct bt_value *extended_obj;
1113 enum bt_value_status status;
1114 };
1115
1116 static
1117 bt_bool extend_map_element(const char *key,
1118 const struct bt_value *extension_obj_elem, void *data)
1119 {
1120 bt_bool ret = BT_TRUE;
1121 struct extend_map_element_data *extend_data = data;
1122 struct bt_value *extension_obj_elem_copy = NULL;
1123
1124 /* Copy object which is to replace the current one */
1125 extend_data->status = bt_value_copy(extension_obj_elem,
1126 &extension_obj_elem_copy);
1127 if (extend_data->status) {
1128 BT_LOGE("Cannot copy map element: addr=%p",
1129 extension_obj_elem);
1130 goto error;
1131 }
1132
1133 BT_ASSERT(extension_obj_elem_copy);
1134
1135 /* Replace in extended object */
1136 extend_data->status = bt_value_map_insert_entry(
1137 extend_data->extended_obj, key,
1138 (void *) extension_obj_elem_copy);
1139 if (extend_data->status) {
1140 BT_LOGE("Cannot replace value in extended value: key=\"%s\", "
1141 "extended-value-addr=%p, element-value-addr=%p",
1142 key, extend_data->extended_obj,
1143 extension_obj_elem_copy);
1144 goto error;
1145 }
1146
1147 goto end;
1148
1149 error:
1150 BT_ASSERT(extend_data->status != BT_VALUE_STATUS_OK);
1151 ret = BT_FALSE;
1152
1153 end:
1154 BT_OBJECT_PUT_REF_AND_RESET(extension_obj_elem_copy);
1155 return ret;
1156 }
1157
1158 enum bt_value_status bt_value_map_extend(
1159 const struct bt_value *base_map_obj,
1160 const struct bt_value *extension_obj,
1161 struct bt_value **extended_map_obj)
1162 {
1163 struct extend_map_element_data extend_data = {
1164 .extended_obj = NULL,
1165 .status = BT_VALUE_STATUS_OK,
1166 };
1167
1168 BT_ASSERT_PRE_NON_NULL(base_map_obj, "Base value object");
1169 BT_ASSERT_PRE_NON_NULL(extension_obj, "Extension value object");
1170 BT_ASSERT_PRE_NON_NULL(extended_map_obj,
1171 "Extended value object (output)");
1172 BT_ASSERT_PRE_VALUE_IS_TYPE(base_map_obj, BT_VALUE_TYPE_MAP);
1173 BT_ASSERT_PRE_VALUE_IS_TYPE(extension_obj, BT_VALUE_TYPE_MAP);
1174 BT_LOGD("Extending map value: base-value-addr=%p, extension-value-addr=%p",
1175 base_map_obj, extension_obj);
1176 *extended_map_obj = NULL;
1177
1178 /* Create copy of base map object to start with */
1179 extend_data.status = bt_value_copy(base_map_obj, extended_map_obj);
1180 if (extend_data.status) {
1181 BT_LOGE("Cannot copy base value: base-value-addr=%p",
1182 base_map_obj);
1183 goto error;
1184 }
1185
1186 BT_ASSERT(extended_map_obj);
1187
1188 /*
1189 * For each key in the extension map object, replace this key
1190 * in the copied map object.
1191 */
1192 extend_data.extended_obj = *extended_map_obj;
1193
1194 if (bt_value_map_foreach_entry_const(extension_obj, extend_map_element,
1195 &extend_data)) {
1196 BT_LOGE("Cannot iterate on the extension object's elements: "
1197 "extension-value-addr=%p", extension_obj);
1198 goto error;
1199 }
1200
1201 if (extend_data.status) {
1202 BT_LOGE("Failed to successfully iterate on the extension object's elements: "
1203 "extension-value-addr=%p", extension_obj);
1204 goto error;
1205 }
1206
1207 BT_LOGD("Extended map value: extended-value-addr=%p",
1208 *extended_map_obj);
1209 goto end;
1210
1211 error:
1212 BT_OBJECT_PUT_REF_AND_RESET(*extended_map_obj);
1213 *extended_map_obj = NULL;
1214
1215 end:
1216 return extend_data.status;
1217 }
1218
1219 enum bt_value_status bt_value_copy(const struct bt_value *object,
1220 struct bt_value **copy_obj)
1221 {
1222 enum bt_value_status status = BT_VALUE_STATUS_OK;
1223
1224 BT_ASSERT_PRE_NON_NULL(object, "Value object");
1225 BT_ASSERT_PRE_NON_NULL(copy_obj, "Value object copy (output)");
1226 BT_LOGD("Copying value object: addr=%p", object);
1227 *copy_obj = copy_funcs[object->type](object);
1228 if (*copy_obj) {
1229 BT_LOGD("Copied value object: copy-value-addr=%p",
1230 copy_obj);
1231 } else {
1232 status = BT_VALUE_STATUS_NOMEM;
1233 *copy_obj = NULL;
1234 BT_LOGE_STR("Failed to copy value object.");
1235 }
1236
1237 return status;
1238 }
1239
1240 bt_bool bt_value_compare(const struct bt_value *object_a,
1241 const struct bt_value *object_b)
1242 {
1243 bt_bool ret = BT_FALSE;
1244
1245 BT_ASSERT_PRE_NON_NULL(object_a, "Value object A");
1246 BT_ASSERT_PRE_NON_NULL(object_b, "Value object B");
1247
1248 if (object_a->type != object_b->type) {
1249 BT_LOGV("Values are different: type mismatch: "
1250 "value-a-addr=%p, value-b-addr=%p, "
1251 "value-a-type=%s, value-b-type=%s",
1252 object_a, object_b,
1253 bt_common_value_type_string(object_a->type),
1254 bt_common_value_type_string(object_b->type));
1255 goto end;
1256 }
1257
1258 ret = compare_funcs[object_a->type](object_a, object_b);
1259
1260 end:
1261 return ret;
1262 }
1263
1264 void bt_value_get_ref(const struct bt_value *value)
1265 {
1266 bt_object_get_ref(value);
1267 }
1268
1269 void bt_value_put_ref(const struct bt_value *value)
1270 {
1271 bt_object_put_ref(value);
1272 }
This page took 0.051655 seconds and 3 git commands to generate.