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