--- /dev/null
+#ifndef _BABELTRACE_OBJECTS_H
+#define _BABELTRACE_OBJECTS_H
+
+/*
+ * Babeltrace
+ *
+ * Basic object system
+ *
+ * Copyright (c) 2015 EfficiOS Inc. and Linux Foundation
+ * Copyright (c) 2015 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/**
+ * @file objects.h
+ * @brief Basic object system
+ *
+ * This is a basic object system API. The following functions allow you
+ * to create, modify, and destroy:
+ *
+ * - \link bt_object_null null objects\endlink
+ * - \link bt_object_bool_create() boolean objects\endlink
+ * - \link bt_object_integer_create() integer objects\endlink
+ * - \link bt_object_float_create() floating point number
+ * objects\endlink
+ * - \link bt_object_string_create() string objects\endlink
+ * - \link bt_object_array_create() array objects\endlink,
+ * containing zero or more objects
+ * - \link bt_object_map_create() map objects\endlink, mapping
+ * string keys to objects
+ *
+ * All the object types above, except for null objects (which always
+ * point to the same \link bt_object_null singleton\endlink), have a
+ * reference count property. Once an object is created, its reference
+ * count is set to 1. When \link bt_object_array_append() appending an
+ * object to an array object\endlink, or \link bt_object_map_insert()
+ * inserting an object into a map object\endlink, its reference count
+ * is incremented, as well as when getting an object back from those
+ * structures. The bt_object_get() and bt_object_put() functions exist
+ * to deal with reference counting. Once you are done with an object,
+ * pass it to bt_object_put().
+ *
+ * A common action with objects is to create or get one, do something
+ * with it, and then put it. To avoid putting it a second time later
+ * (if an error occurs, for example), the variable is often reset to
+ * \c NULL after putting the object it points to. Since this is so
+ * common, you can use the BT_OBJECT_PUT() macro, which does just that:
+ *
+ * \code{.c}
+ * struct bt_object *int_obj = bt_object_integer_create_init(34);
+ *
+ * if (!int_obj) {
+ * goto error;
+ * }
+ *
+ * // stuff, which could jump to error
+ *
+ * BT_OBJECT_PUT(int_obj);
+ *
+ * // stuff, which could jump to error
+ *
+ * return 0;
+ *
+ * error:
+ * // safe, even if int_obj is NULL
+ * BT_OBJECT_PUT(int_obj);
+ * \endcode
+ *
+ * Another common manipulation is to move the ownership of an object
+ * from one variable to another: since the reference count is not
+ * incremented, and since, to avoid errors, two variables should not
+ * point to same object without each of them having their own reference,
+ * it is best practice to set the original variable to \c NULL. This
+ * too can be accomplished in a single step using the BT_OBJECT_MOVE()
+ * macro:
+ *
+ * \code{.c}
+ * struct bt_object *int_obj2 = NULL;
+ * struct bt_object *int_obj = bt_object_integer_create_init(-23);
+ *
+ * if (!int_obj) {
+ * goto error;
+ * }
+ *
+ * // stuff, which could jump to error
+ *
+ * BT_OBJECT_MOVE(int_obj2, int_obj);
+ *
+ * // stuff, which could jump to error
+ *
+ * return 0;
+ *
+ * error:
+ * // safe, since only one of int_obj/int_obj2 (or none)
+ * // points to the object
+ * BT_OBJECT_PUT(int_obj);
+ * BT_OBJECT_PUT(int_obj2);
+ * \endcode
+ *
+ * You can create a deep copy of any object using the bt_object_copy()
+ * function. You can compare two given objects using
+ * bt_object_compare().
+ *
+ * @author Philippe Proulx <pproulx@efficios.com>
+ * @bug No known bugs
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Object type.
+ */
+enum bt_object_type {
+ /** Unknown object, used as an error code. */
+ BT_OBJECT_TYPE_UNKNOWN = -1,
+
+ /** Null object. */
+ BT_OBJECT_TYPE_NULL = 0,
+
+ /** Boolean object (holds \c true or \c false). */
+ BT_OBJECT_TYPE_BOOL = 1,
+
+ /** Integer (holds a signed 64-bit integer value). */
+ BT_OBJECT_TYPE_INTEGER = 2,
+
+ /**
+ * Floating point number object (holds a \c double value).
+ */
+ BT_OBJECT_TYPE_FLOAT = 3,
+
+ /** String object. */
+ BT_OBJECT_TYPE_STRING = 4,
+
+ /** Array object. */
+ BT_OBJECT_TYPE_ARRAY = 5,
+
+ /** Map object. */
+ BT_OBJECT_TYPE_MAP = 6,
+};
+
+/**
+ * Object.
+ */
+struct bt_object;
+
+/**
+ * The null object singleton.
+ *
+ * Use this everytime you need a null objet. The null objet singleton
+ * has no reference count; there's only one. You may compare any object
+ * to the null singleton to find out if it's a null object, or otherwise
+ * use bt_object_is_null().
+ *
+ * Functions of this API return this when the object is actually a
+ * null object (of type \link bt_object_type::BT_OBJECT_TYPE_NULL
+ * <code>BT_OBJECT_TYPE_NULL</code>\endlink), whereas \c NULL means an error
+ * of some sort.
+ */
+extern struct bt_object *bt_object_null;
+
+/**
+ * User function type for bt_object_map_foreach().
+ *
+ * \p object is a \i weak reference; you must pass it to
+ * bt_object_get() to get your own reference.
+ *
+ * Return \c true to continue the loop, or \c false to break it.
+ *
+ * @param key Key of map entry
+ * @param object Object of map entry (weak reference)
+ * @param data User data
+ * @returns \c true to continue the loop
+ */
+typedef bool (* bt_object_map_foreach_cb)(const char *key,
+ struct bt_object *object, void *data);
+
+/**
+ * Puts the object \p _object (calls bt_object_put() on it), and resets
+ * the variable to \c NULL.
+ *
+ * This is something that is often done when putting and object;
+ * resetting the variable to \c NULL makes sure it cannot be put a
+ * second time later.
+ *
+ * @param _object Object to put
+ *
+ * @see BT_OBJECT_MOVE() (moves an object from one variable to the other
+ * without putting it)
+ */
+#define BT_OBJECT_PUT(_object) \
+ do { \
+ bt_object_put(_object); \
+ (_object) = NULL; \
+ } while (0)
+
+/**
+ * Moves the object referenced by the variable \p _src_object to the
+ * \p _dst_object variable, then resets \p _src_object to \c NULL.
+ *
+ * The object's reference count is <b>not changed</b>. Resetting
+ * \p _src_object to \c NULL ensures the object will not be put
+ * twice later; its ownership is indeed \i moved from the source
+ * variable to the destination variable.
+ *
+ * @param _src_object Source object variable
+ * @param _dst_object Destination object variable
+ */
+#define BT_OBJECT_MOVE(_dst_object, _src_object) \
+ do { \
+ (_dst_object) = (_src_object); \
+ (_src_object) = NULL; \
+ } while (0)
+
+/**
+ * Increments the reference count of \p object.
+ *
+ * @param object Object of which to increment the reference count
+ */
+extern void bt_object_get(struct bt_object *object);
+
+/**
+ * Decrements the reference count of \p object, destroying it when this
+ * count reaches 0.
+ *
+ * @param object Object of which to decrement the reference count
+ *
+ * @see BT_OBJECT_PUT() (puts an object and resets the variable to
+ * \c NULL)
+ */
+extern void bt_object_put(struct bt_object *object);
+
+/**
+ * Returns the type of \p object.
+ *
+ * @param object Object of which to get the type
+ * @returns Object's type, or
+ * \link bt_object_type::BT_OBJECT_TYPE_NULL
+ * <code>BT_OBJECT_TYPE_UNKNOWN</code>\endlink
+ * on error
+ *
+ * @see enum bt_object_type (object types)
+ */
+extern enum bt_object_type bt_object_get_type(const struct bt_object *object);
+
+/**
+ * Checks whether \p object is a null object. The only valid null
+ * object is \ref bt_object_null.
+ *
+ * @param object Object to check
+ * @returns \c true if \p object is a null object
+ */
+bool bt_object_is_null(const struct bt_object *object)
+{
+ return bt_object_get_type(object) == BT_OBJECT_TYPE_NULL;
+}
+
+/**
+ * Checks whether \p object is a boolean object.
+ *
+ * @param object Object to check
+ * @returns \c true if \p object is a boolean object
+ */
+bool bt_object_is_bool(const struct bt_object *object)
+{
+ return bt_object_get_type(object) == BT_OBJECT_TYPE_BOOL;
+}
+
+/**
+ * Checks whether \p object is an integer object.
+ *
+ * @param object Object to check
+ * @returns \c true if \p object is an integer object
+ */
+bool bt_object_is_integer(const struct bt_object *object)
+{
+ return bt_object_get_type(object) == BT_OBJECT_TYPE_INTEGER;
+}
+
+/**
+ * Checks whether \p object is a floating point number object.
+ *
+ * @param object Object to check
+ * @returns \c true if \p object is a floating point number object
+ */
+bool bt_object_is_float(const struct bt_object *object)
+{
+ return bt_object_get_type(object) == BT_OBJECT_TYPE_FLOAT;
+}
+
+/**
+ * Checks whether \p object is a string object.
+ *
+ * @param object Object to check
+ * @returns \c true if \p object is a string object
+ */
+bool bt_object_is_string(const struct bt_object *object)
+{
+ return bt_object_get_type(object) == BT_OBJECT_TYPE_STRING;
+}
+
+/**
+ * Checks whether \p object is an array object.
+ *
+ * @param object Object to check
+ * @returns \c true if \p object is an array object
+ */
+bool bt_object_is_array(const struct bt_object *object)
+{
+ return bt_object_get_type(object) == BT_OBJECT_TYPE_ARRAY;
+}
+
+/**
+ * Checks whether \p object is a map object.
+ *
+ * @param object Object to check
+ * @returns \c true if \p object is a map object
+ */
+bool bt_object_is_map(const struct bt_object *object)
+{
+ return bt_object_get_type(object) == BT_OBJECT_TYPE_MAP;
+}
+
+/**
+ * Creates a boolean object. The created boolean object's initial value
+ * is \c false.
+ *
+ * The created object's reference count is set to 1.
+ *
+ * @returns Created object on success, or \c NULL on error
+ */
+extern struct bt_object *bt_object_bool_create(void);
+
+/**
+ * Creates a boolean object with its initial value set to \p val.
+ *
+ * The created object's reference count is set to 1.
+ *
+ * @param val Initial value
+ * @returns Created object on success, or \c NULL on error
+ */
+extern struct bt_object *bt_object_bool_create_init(bool val);
+
+/**
+ * Creates an integer object. The created integer object's initial value
+ * is 0.
+ *
+ * The created object's reference count is set to 1.
+ *
+ * @returns Created object on success, or \c NULL on error
+ */
+extern struct bt_object *bt_object_integer_create(void);
+
+/**
+ * Creates an integer object with its initial value set to \p val.
+ *
+ * The created object's reference count is set to 1.
+ *
+ * @param val Initial value
+ * @returns Created object on success, or \c NULL on error
+ */
+extern struct bt_object *bt_object_integer_create_init(int64_t val);
+
+/**
+ * Creates a floating point number object. The created floating point
+ * number object's initial value is 0.
+ *
+ * The created object's reference count is set to 1.
+ *
+ * @returns Created object on success, or \c NULL on error
+ */
+extern struct bt_object *bt_object_float_create(void);
+
+/**
+ * Creates a floating point number object with its initial value set
+ * to \p val.
+ *
+ * The created object's reference count is set to 1.
+ *
+ * @param val Initial value
+ * @returns Created object on success, or \c NULL on error
+ */
+extern struct bt_object *bt_object_float_create_init(double val);
+
+/**
+ * Creates a string object. The string object is initially empty.
+ *
+ * The created object's reference count is set to 1.
+ *
+ * @returns Created object on success, or \c NULL on error
+ */
+extern struct bt_object *bt_object_string_create(void);
+
+/**
+ * Creates a string object with its initial value set to \p val.
+ *
+ * \p val is copied.
+ *
+ * The created object's reference count is set to 1.
+ *
+ * @param val Initial value (will be copied)
+ * @returns Created object on success, or \c NULL on error
+ */
+extern struct bt_object *bt_object_string_create_init(const char *val);
+
+/**
+ * Creates an empty array object.
+ *
+ * The created object's reference count is set to 1.
+ *
+ * @returns Created object on success, or \c NULL on error
+ */
+extern struct bt_object *bt_object_array_create(void);
+
+/**
+ * Creates an empty map object.
+ *
+ * The created object's reference count is set to 1.
+ *
+ * @returns Created object on success, or \c NULL on error
+ */
+extern struct bt_object *bt_object_map_create(void);
+
+/**
+ * Gets the boolean value of the boolean objet \p bool_obj.
+ *
+ * @param bool_obj Boolean object
+ * @param val Returned boolean value
+ * @returns 0 on success, negative value on error
+ */
+extern int bt_object_bool_get(const struct bt_object *bool_obj, bool *val);
+
+/**
+ * Sets the boolean value of the boolean object \p bool_obj to \p val.
+ *
+ * @param bool_obj Boolean object
+ * @param val New boolean value
+ * @returns 0 on success, negative value on error
+ */
+extern int bt_object_bool_set(struct bt_object *bool_obj, bool val);
+
+/**
+ * Gets the integer value of the integer objet \p integer_obj.
+ *
+ * @param integer_obj Integer object
+ * @param val Returned integer value
+ * @returns 0 on success, negative value on error
+ */
+extern int bt_object_integer_get(const struct bt_object *integer_obj,
+ int64_t *val);
+
+/**
+ * Sets the integer value of the integer object \p integer_obj to
+ * \p val.
+ *
+ * @param integer_obj Integer object
+ * @param val New integer value
+ * @returns 0 on success, negative value on error
+ */
+extern int bt_object_integer_set(struct bt_object *integer_obj, int64_t val);
+
+/**
+ * Gets the floating point number value of the floating point number
+ * objet \p float_obj.
+ *
+ * @param float_obj Floating point number object
+ * @param val Returned floating point number value
+ * @returns 0 on success, negative value on error
+ */
+extern int bt_object_float_get(const struct bt_object *float_obj, double *val);
+
+/**
+ * Sets the floating point number value of the floating point number
+ * object \p float_obj to \p val.
+ *
+ * @param float_obj Floating point number object
+ * @param val New floating point number value
+ * @returns 0 on success, negative value on error
+ */
+extern int bt_object_float_set(struct bt_object *float_obj, double val);
+
+/**
+ * Gets the string value of the string objet \p string_obj. The
+ * returned string is valid as long as this object exists and is not
+ * modified.
+ *
+ * @param string_obj String object
+ * @returns String value, or \c NULL on error
+ */
+extern const char *bt_object_string_get(const struct bt_object *string_obj);
+
+/**
+ * Sets the string value of the string object \p string_obj to
+ * \p val.
+ *
+ * \p val is copied.
+ *
+ * @param string_obj String object
+ * @param val New string value (copied)
+ * @returns 0 on success, negative value on error
+ */
+extern int bt_object_string_set(struct bt_object *string_obj, const char *val);
+
+/**
+ * Gets the size of the array object \p array_obj, that is, the number
+ * of elements contained in \p array_obj.
+ *
+ * @param array_obj Array object
+ * @returns Array size, or a negative value on error
+ */
+extern int bt_object_array_size(const struct bt_object *array_obj);
+
+/**
+ * Returns \c true if the array object \p array_obj.
+ *
+ * @param array_obj Array object
+ * @returns \c true if \p array_obj is empty
+ */
+extern bool bt_object_array_is_empty(const struct bt_object *array_obj);
+
+/**
+ * Gets the element object of the array object \p array_obj at the
+ * index \p index.
+ *
+ * The returned object's reference count is incremented, unless it's
+ * a null object.
+ *
+ * @param array_obj Array object
+ * @param index Index of element to get
+ * @returns Element object at index \p index on success,
+ * or \c NULL on error
+ */
+extern struct bt_object *bt_object_array_get(const struct bt_object *array_obj,
+ size_t index);
+
+/**
+ * Appends the element object \p element_obj to the array object
+ * \p array_obj.
+ *
+ * The appended object's reference count is incremented, unless it's
+ * a null object.
+ *
+ * @param array_obj Array object
+ * @param element_obj Element object to append
+ * @returns 0 on success, or a negative value on error
+ */
+extern int bt_object_array_append(struct bt_object *array_obj,
+ struct bt_object *element_obj);
+
+/**
+ * Appends the boolean value \p val to the array object \p array_obj.
+ * This is a convenience function which creates the underlying boolean
+ * object before appending it.
+ *
+ * The created boolean object's reference count is set to 1.
+ *
+ * @param array_obj Array object
+ * @param val Boolean value to append
+ * @returns 0 on success, or a negative value on error
+ */
+extern int bt_object_array_append_bool(struct bt_object *array_obj, bool val);
+
+/**
+ * Appends the integer value \p val to the array object \p array_obj.
+ * This is a convenience function which creates the underlying integer
+ * object before appending it.
+ *
+ * The created integer object's reference count is set to 1.
+ *
+ * @param array_obj Array object
+ * @param val Integer value to append
+ * @returns 0 on success, or a negative value on error
+ */
+extern int bt_object_array_append_integer(struct bt_object *array_obj,
+ int64_t val);
+
+/**
+ * Appends the floating point number value \p val to the array object
+ * \p array_obj. This is a convenience function which creates the
+ * underlying floating point number object before appending it.
+ *
+ * The created floating point number object's reference count is
+ * set to 1.
+ *
+ * @param array_obj Array object
+ * @param val Floating point number value to append
+ * @returns 0 on success, or a negative value on error
+ */
+extern int bt_object_array_append_float(struct bt_object *array_obj,
+ double val);
+
+/**
+ * Appends the string value \p val to the array object \p array_obj.
+ * This is a convenience function which creates the underlying string
+ * object before appending it.
+ *
+ * \p val is copied.
+ *
+ * The created string object's reference count is set to 1.
+ *
+ * @param array_obj Array object
+ * @param val String value to append (copied)
+ * @returns 0 on success, or a negative value on error
+ */
+extern int bt_object_array_append_string(struct bt_object *array_obj,
+ const char *val);
+
+/**
+ * Appends an empty array object to the array object \p array_obj.
+ * This is a convenience function which creates the underlying array
+ * object before appending it.
+ *
+ * The created array object's reference count is set to 1.
+ *
+ * @param array_obj Array object
+ * @returns 0 on success, or a negative value on error
+ */
+extern int bt_object_array_append_array(struct bt_object *array_obj);
+
+/**
+ * Appends an empty map object to the array object \p array_obj. This
+ * is a convenience function which creates the underlying map object
+ * before appending it.
+ *
+ * The created map object's reference count is set to 1.
+ *
+ * @param array_obj Array object
+ * @returns 0 on success, or a negative value on error
+ */
+extern int bt_object_array_append_map(struct bt_object *array_obj);
+
+/**
+ * Gets the size of a map object, that is, the number of elements
+ * contained in a map object.
+ *
+ * @param map_obj Map object
+ * @returns Map size, or a negative value on error
+ */
+extern int bt_object_map_size(const struct bt_object *map_obj);
+
+/**
+ * Returns \c true if the map object \p map_obj.
+ *
+ * @param map_obj Map object
+ * @returns \c true if \p map_obj is empty
+ */
+extern bool bt_object_map_is_empty(const struct bt_object *map_obj);
+
+/**
+ * Gets the element object associated with the key \p key within the
+ * map object \p map_obj.
+ *
+ * The returned object's reference count is incremented, unless it's
+ * a null object.
+ *
+ * @param map_obj Map object
+ * @param key Key of the element to get
+ * @returns Element object associated with the key \p key
+ * on success, or \c NULL on error
+ */
+extern struct bt_object *bt_object_map_get(const struct bt_object *map_obj,
+ const char *key);
+
+/**
+ * Calls a provided user function \p cb for each element of the map
+ * object \p map_obj.
+ *
+ * The object passed to the user function is a <b>weak reference</b>:
+ * you must call bt_object_get() on it to obtain your own reference.
+ *
+ * The key passed to the user function is only valid in the scope of
+ * this user function.
+ *
+ * The user function must return \c true to continue the loop, or
+ * \c false to break it.
+ *
+ * @param map_obj Map object
+ * @param cb User function to call back
+ * @param data User data passed to the user function
+ * @returns 0 on success, or a negative value on error
+ * (the user function breaking the loop is \b not
+ * considered an error here)
+ */
+extern int bt_object_map_foreach(const struct bt_object *map_obj,
+ bt_object_map_foreach_cb cb, void *data);
+
+/**
+ * Returns whether or not the map object \p map_obj contains the
+ * key \p key.
+ *
+ * @param map_obj Map object
+ * @param key Key to check
+ * @returns \c true if \p map_obj contains the key \p key,
+ * or \c false if it doesn't have \p key or
+ * on error
+ */
+extern bool bt_object_map_has_key(const struct bt_object *map_obj,
+ const char *key);
+
+/**
+ * Inserts the element object \p element_obj associated with the key
+ * \p key into the map object \p map_obj. If \p key exists in
+ * \p map_obj, the associated element object is first put, and then
+ * replaced by \p element_obj.
+ *
+ * \p key is copied.
+ *
+ * The inserted object's reference count is incremented, unless it's
+ * a null object.
+ *
+ * @param map_obj Map object
+ * @param key Key (copied) of object to insert
+ * @param element_obj Element object to insert, associated with the
+ * key \p key
+ * @returns 0 on success, or a negative value on error
+ */
+extern int bt_object_map_insert(struct bt_object *map_obj,
+ const char *key, struct bt_object *element_obj);
+
+/**
+ * Inserts the boolean value \p val associated with the key \p key into
+ * the map object \p map_obj. This is a convenience function which
+ * creates the underlying boolean object before inserting it.
+ *
+ * \p key is copied.
+ *
+ * The created boolean object's reference count is set to 1.
+ *
+ * @param map_obj Map object
+ * @param key Key (copied) of boolean value to insert
+ * @param val Boolean value to insert, associated with the
+ * key \p key
+ * @returns 0 on success, or a negative value on error
+ */
+extern int bt_object_map_insert_bool(struct bt_object *map_obj,
+ const char *key, bool val);
+
+/**
+ * Inserts the integer value \p val associated with the key \p key into
+ * the map object \p map_obj. This is a convenience function which
+ * creates the underlying integer object before inserting it.
+ *
+ * \p key is copied.
+ *
+ * The created integer object's reference count is set to 1.
+ *
+ * @param map_obj Map object
+ * @param key Key (copied) of integer value to insert
+ * @param val Integer value to insert, associated with the
+ * key \p key
+ * @returns 0 on success, or a negative value on error
+ */
+extern int bt_object_map_insert_integer(struct bt_object *map_obj,
+ const char *key, int64_t val);
+
+/**
+ * Inserts the floating point number value \p val associated with the
+ * key \p key into the map object \p map_obj. This is a convenience
+ * function which creates the underlying floating point number object
+ * before inserting it.
+ *
+ * \p key is copied.
+ *
+ * The created floating point number object's reference count is
+ * set to 1.
+ *
+ * @param map_obj Map object
+ * @param key Key (copied) of floating point number value to
+ * insert
+ * @param val Floating point number value to insert,
+ * associated with the key \p key
+ * @returns 0 on success, or a negative value on error
+ */
+extern int bt_object_map_insert_float(struct bt_object *map_obj,
+ const char *key, double val);
+
+/**
+ * Inserts the string value \p val associated with the key \p key into
+ * the map object \p map_obj. This is a convenience function which
+ * creates the underlying string object before inserting it.
+ *
+ * \p val and \p key are copied.
+ *
+ * The created string object's reference count is set to 1.
+ *
+ * @param map_obj Map object
+ * @param key Key (copied) of string value to insert
+ * @param val String value to insert, associated with the
+ * key \p key
+ * @returns 0 on success, or a negative value on error
+ */
+extern int bt_object_map_insert_string(struct bt_object *map_obj,
+ const char *key, const char *val);
+
+/**
+ * Inserts an empty array object associated with the key \p key into
+ * the map object \p map_obj. This is a convenience function which
+ * creates the underlying array object before inserting it.
+ *
+ * \p key is copied.
+ *
+ * The created array object's reference count is set to 1.
+ *
+ * @param map_obj Map object
+ * @param key Key (copied) of empty array to insert
+ * @returns 0 on success, or a negative value on error
+ */
+extern int bt_object_map_insert_array(struct bt_object *map_obj,
+ const char *key);
+
+/**
+ * Inserts an empty map object associated with the key \p key into
+ * the map object \p map_obj. This is a convenience function which
+ * creates the underlying map object before inserting it.
+ *
+ * \p key is copied.
+ *
+ * The created map object's reference count is set to 1.
+ *
+ * @param map_obj Map object
+ * @param key Key (copied) of empty map to insert
+ * @returns 0 on success, or a negative value on error
+ */
+extern int bt_object_map_insert_map(struct bt_object *map_obj,
+ const char *key);
+
+/**
+ * Creates a deep copy of the object \p object.
+ *
+ * The created object's reference count is set to 1, unless
+ * \p object is a null object.
+ *
+ * @param object Object to copy
+ * @returns Deep copy of \p object on success, or \c NULL
+ * on error
+ */
+extern struct bt_object *bt_object_copy(const struct bt_object *object);
+
+/**
+ * Compares the objects \p object_a and \p object_b and returns \c true
+ * if they have the same content.
+ *
+ * @param object_a Object A
+ * @param object_B Object B
+ * @returns \c true if \p object_a and \p object_b have the
+ * same content, or \c false if they differ or on
+ * error
+ */
+extern bool bt_object_compare(const struct bt_object *object_a,
+ const struct bt_object *object_b);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _BABELTRACE_OBJECTS_H */
--- /dev/null
+/*
+ * objects.c: basic object system
+ *
+ * Babeltrace Library
+ *
+ * Copyright (c) 2015 EfficiOS Inc. and Linux Foundation
+ * Copyright (c) 2015 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <string.h>
+#include <babeltrace/ctf-writer/ref-internal.h>
+#include <babeltrace/compiler.h>
+#include <glib.h>
+#include <babeltrace/objects.h>
+
+#define BT_OBJECT_FROM_CONCRETE(_concrete) ((struct bt_object *) (_concrete))
+#define BT_OBJECT_TO_BOOL(_base) ((struct bt_object_bool *) (_base))
+#define BT_OBJECT_TO_INTEGER(_base) ((struct bt_object_integer *) (_base))
+#define BT_OBJECT_TO_FLOAT(_base) ((struct bt_object_float *) (_base))
+#define BT_OBJECT_TO_STRING(_base) ((struct bt_object_string *) (_base))
+#define BT_OBJECT_TO_ARRAY(_base) ((struct bt_object_array *) (_base))
+#define BT_OBJECT_TO_MAP(_base) ((struct bt_object_map *) (_base))
+
+struct bt_object {
+ enum bt_object_type type;
+ struct bt_ctf_ref ref_count;
+};
+
+static
+struct bt_object bt_object_null_instance = {
+ .type = BT_OBJECT_TYPE_NULL,
+};
+
+struct bt_object *bt_object_null = &bt_object_null_instance;
+
+struct bt_object_bool {
+ struct bt_object base;
+ bool value;
+};
+
+struct bt_object_integer {
+ struct bt_object base;
+ int64_t value;
+};
+
+struct bt_object_float {
+ struct bt_object base;
+ double value;
+};
+
+struct bt_object_string {
+ struct bt_object base;
+ GString *gstr;
+};
+
+struct bt_object_array {
+ struct bt_object base;
+ GArray *garray;
+};
+
+struct bt_object_map {
+ struct bt_object base;
+ GHashTable *ght;
+};
+
+static
+void bt_object_string_destroy(struct bt_object *object)
+{
+ struct bt_object_string *string_obj = BT_OBJECT_TO_STRING(object);
+
+ g_string_free(string_obj->gstr, TRUE);
+}
+
+static
+void bt_object_array_destroy(struct bt_object *object)
+{
+ int x;
+ struct bt_object_array *array_obj = BT_OBJECT_TO_ARRAY(object);
+
+ for (x = 0; x < array_obj->garray->len; ++x) {
+ struct bt_object *el_obj;
+
+ el_obj = g_array_index(array_obj->garray,
+ struct bt_object *, x);
+ bt_object_put(el_obj);
+ }
+
+ g_array_free(array_obj->garray, TRUE);
+}
+
+static
+void bt_object_map_destroy(struct bt_object *object)
+{
+ struct bt_object_map *map = BT_OBJECT_TO_MAP(object);
+
+ /*
+ * Hash table's registered value destructor will take care of
+ * putting each contained object. Keys are GQuarks and cannot
+ * be destroyed anyway.
+ */
+ g_hash_table_destroy(map->ght);
+}
+
+static
+void (* const destroy_funcs[])(struct bt_object *) = {
+ [BT_OBJECT_TYPE_NULL] = NULL,
+ [BT_OBJECT_TYPE_BOOL] = NULL,
+ [BT_OBJECT_TYPE_INTEGER] = NULL,
+ [BT_OBJECT_TYPE_FLOAT] = NULL,
+ [BT_OBJECT_TYPE_STRING] = bt_object_string_destroy,
+ [BT_OBJECT_TYPE_ARRAY] = bt_object_array_destroy,
+ [BT_OBJECT_TYPE_MAP] = bt_object_map_destroy,
+};
+
+static
+struct bt_object *bt_object_null_copy(const struct bt_object *null_obj)
+{
+ return bt_object_null;
+}
+
+static
+struct bt_object *bt_object_bool_copy(const struct bt_object *bool_obj)
+{
+ return bt_object_bool_create_init(BT_OBJECT_TO_BOOL(bool_obj)->value);
+}
+
+static
+struct bt_object *bt_object_integer_copy(const struct bt_object *integer_obj)
+{
+ return bt_object_integer_create_init(
+ BT_OBJECT_TO_INTEGER(integer_obj)->value);
+}
+
+static
+struct bt_object *bt_object_float_copy(const struct bt_object *float_obj)
+{
+ return bt_object_float_create_init(
+ BT_OBJECT_TO_FLOAT(float_obj)->value);
+}
+
+static
+struct bt_object *bt_object_string_copy(const struct bt_object *string_obj)
+{
+ return bt_object_string_create_init(
+ BT_OBJECT_TO_STRING(string_obj)->gstr->str);
+}
+
+static
+struct bt_object *bt_object_array_copy(const struct bt_object *array_obj)
+{
+ int x;
+ int ret;
+ struct bt_object *copy_obj;
+ struct bt_object_array *typed_array_obj;
+
+ typed_array_obj = BT_OBJECT_TO_ARRAY(array_obj);
+ copy_obj = bt_object_array_create();
+
+ if (!copy_obj) {
+ goto end;
+ }
+
+ for (x = 0; x < typed_array_obj->garray->len; ++x) {
+ struct bt_object *element_obj_copy;
+ struct bt_object *element_obj =
+ bt_object_array_get(array_obj, x);
+
+ if (!element_obj) {
+ BT_OBJECT_PUT(copy_obj);
+ goto end;
+ }
+
+ element_obj_copy = bt_object_copy(element_obj);
+ BT_OBJECT_PUT(element_obj);
+
+ if (!element_obj_copy) {
+ BT_OBJECT_PUT(copy_obj);
+ goto end;
+ }
+
+ ret = bt_object_array_append(copy_obj, element_obj_copy);
+ BT_OBJECT_PUT(element_obj_copy);
+
+ if (ret) {
+ BT_OBJECT_PUT(copy_obj);
+ goto end;
+ }
+ }
+
+end:
+ return copy_obj;
+}
+
+static
+struct bt_object *bt_object_map_copy(const struct bt_object *map_obj)
+{
+ int ret;
+ GHashTableIter iter;
+ gpointer key, element_obj;
+ struct bt_object *copy_obj;
+ struct bt_object *element_obj_copy;
+ struct bt_object_map *typed_map_obj;
+
+ typed_map_obj = BT_OBJECT_TO_MAP(map_obj);
+ copy_obj = bt_object_map_create();
+
+ if (!copy_obj) {
+ goto end;
+ }
+
+ g_hash_table_iter_init(&iter, typed_map_obj->ght);
+
+ while (g_hash_table_iter_next(&iter, &key, &element_obj)) {
+ const char *key_str = g_quark_to_string((unsigned long) key);
+
+ element_obj_copy = bt_object_copy(element_obj);
+
+ if (!element_obj_copy) {
+ BT_OBJECT_PUT(copy_obj);
+ goto end;
+ }
+
+ ret = bt_object_map_insert(copy_obj, key_str, element_obj_copy);
+ BT_OBJECT_PUT(element_obj_copy);
+
+ if (ret) {
+ BT_OBJECT_PUT(copy_obj);
+ goto end;
+ }
+ }
+
+end:
+ return copy_obj;
+}
+
+static
+struct bt_object *(* const copy_funcs[])(const struct bt_object *) = {
+ [BT_OBJECT_TYPE_NULL] = bt_object_null_copy,
+ [BT_OBJECT_TYPE_BOOL] = bt_object_bool_copy,
+ [BT_OBJECT_TYPE_INTEGER] = bt_object_integer_copy,
+ [BT_OBJECT_TYPE_FLOAT] = bt_object_float_copy,
+ [BT_OBJECT_TYPE_STRING] = bt_object_string_copy,
+ [BT_OBJECT_TYPE_ARRAY] = bt_object_array_copy,
+ [BT_OBJECT_TYPE_MAP] = bt_object_map_copy,
+};
+
+static
+bool bt_object_null_compare(const struct bt_object *object_a,
+ const struct bt_object *object_b)
+{
+ /*
+ * Always true since bt_object_compare() already checks if both
+ * object_a and object_b have the same type, and in the case of
+ * null objects, they're always the same if it is so.
+ */
+ return true;
+}
+
+static
+bool bt_object_bool_compare(const struct bt_object *object_a,
+ const struct bt_object *object_b)
+{
+ return BT_OBJECT_TO_BOOL(object_a)->value ==
+ BT_OBJECT_TO_BOOL(object_b)->value;
+}
+
+static
+bool bt_object_integer_compare(const struct bt_object *object_a,
+ const struct bt_object *object_b)
+{
+ return BT_OBJECT_TO_INTEGER(object_a)->value ==
+ BT_OBJECT_TO_INTEGER(object_b)->value;
+}
+
+static
+bool bt_object_float_compare(const struct bt_object *object_a,
+ const struct bt_object *object_b)
+{
+ return BT_OBJECT_TO_FLOAT(object_a)->value ==
+ BT_OBJECT_TO_FLOAT(object_b)->value;
+}
+
+static
+bool bt_object_string_compare(const struct bt_object *object_a,
+ const struct bt_object *object_b)
+{
+ return !strcmp(BT_OBJECT_TO_STRING(object_a)->gstr->str,
+ BT_OBJECT_TO_STRING(object_b)->gstr->str);
+}
+
+static
+bool bt_object_array_compare(const struct bt_object *object_a,
+ const struct bt_object *object_b)
+{
+ int x;
+ bool ret = true;
+ const struct bt_object_array *array_obj_a =
+ BT_OBJECT_TO_ARRAY(object_a);
+
+ if (bt_object_array_size(object_a) != bt_object_array_size(object_b)) {
+ ret = false;
+ goto end;
+ }
+
+ for (x = 0; x < array_obj_a->garray->len; ++x) {
+ struct bt_object *element_obj_a;
+ struct bt_object *element_obj_b;
+
+ element_obj_a = bt_object_array_get(object_a, x);
+ element_obj_b = bt_object_array_get(object_b, x);
+
+ if (!bt_object_compare(element_obj_a, element_obj_b)) {
+ BT_OBJECT_PUT(element_obj_a);
+ BT_OBJECT_PUT(element_obj_b);
+ ret = false;
+ goto end;
+ }
+
+ BT_OBJECT_PUT(element_obj_a);
+ BT_OBJECT_PUT(element_obj_b);
+ }
+
+end:
+ return ret;
+}
+
+static
+bool bt_object_map_compare(const struct bt_object *object_a,
+ const struct bt_object *object_b)
+{
+ bool ret = true;
+ GHashTableIter iter;
+ gpointer key, element_obj_a;
+ const struct bt_object_map *map_obj_a = BT_OBJECT_TO_MAP(object_a);
+
+ if (bt_object_map_size(object_a) != bt_object_map_size(object_b)) {
+ ret = false;
+ goto end;
+ }
+
+ g_hash_table_iter_init(&iter, map_obj_a->ght);
+
+ while (g_hash_table_iter_next(&iter, &key, &element_obj_a)) {
+ struct bt_object *element_obj_b;
+ const char *key_str = g_quark_to_string((unsigned long) key);
+
+ element_obj_b = bt_object_map_get(object_b, key_str);
+
+ if (!bt_object_compare(element_obj_a, element_obj_b)) {
+ BT_OBJECT_PUT(element_obj_b);
+ ret = false;
+ goto end;
+ }
+
+ BT_OBJECT_PUT(element_obj_b);
+ }
+
+end:
+ return ret;
+}
+
+static
+bool (* const compare_funcs[])(const struct bt_object *,
+ const struct bt_object *) = {
+ [BT_OBJECT_TYPE_NULL] = bt_object_null_compare,
+ [BT_OBJECT_TYPE_BOOL] = bt_object_bool_compare,
+ [BT_OBJECT_TYPE_INTEGER] = bt_object_integer_compare,
+ [BT_OBJECT_TYPE_FLOAT] = bt_object_float_compare,
+ [BT_OBJECT_TYPE_STRING] = bt_object_string_compare,
+ [BT_OBJECT_TYPE_ARRAY] = bt_object_array_compare,
+ [BT_OBJECT_TYPE_MAP] = bt_object_map_compare,
+};
+
+static
+void bt_object_destroy(struct bt_ctf_ref *ref_count)
+{
+ struct bt_object *object;
+
+ object = container_of(ref_count, struct bt_object, ref_count);
+ assert(object->type != BT_OBJECT_TYPE_UNKNOWN);
+
+ if (bt_object_is_null(object)) {
+ return;
+ }
+
+ if (destroy_funcs[object->type]) {
+ destroy_funcs[object->type](object);
+ }
+
+ g_free(object);
+}
+
+void bt_object_get(struct bt_object *object)
+{
+ if (!object) {
+ goto skip;
+ }
+
+ bt_ctf_ref_get(&object->ref_count);
+
+skip:
+ return;
+}
+
+void bt_object_put(struct bt_object *object)
+{
+ if (!object) {
+ goto skip;
+ }
+
+ bt_ctf_ref_put(&object->ref_count, bt_object_destroy);
+
+skip:
+ return;
+}
+
+enum bt_object_type bt_object_get_type(const struct bt_object *object)
+{
+ if (!object) {
+ return BT_OBJECT_TYPE_UNKNOWN;
+ }
+
+ return object->type;
+}
+
+static
+struct bt_object bt_object_create_base(enum bt_object_type type)
+{
+ struct bt_object base;
+
+ base.type = type;
+ bt_ctf_ref_init(&base.ref_count);
+
+ return base;
+}
+
+struct bt_object *bt_object_bool_create_init(bool val)
+{
+ struct bt_object_bool *bool_obj;
+
+ bool_obj = g_new0(struct bt_object_bool, 1);
+
+ if (!bool_obj) {
+ goto end;
+ }
+
+ bool_obj->base = bt_object_create_base(BT_OBJECT_TYPE_BOOL);
+ bool_obj->value = val;
+
+end:
+ return BT_OBJECT_FROM_CONCRETE(bool_obj);
+}
+
+struct bt_object *bt_object_bool_create(void)
+{
+ return bt_object_bool_create_init(false);
+}
+
+struct bt_object *bt_object_integer_create_init(int64_t val)
+{
+ struct bt_object_integer *integer_obj;
+
+ integer_obj = g_new0(struct bt_object_integer, 1);
+
+ if (!integer_obj) {
+ goto end;
+ }
+
+ integer_obj->base = bt_object_create_base(BT_OBJECT_TYPE_INTEGER);
+ integer_obj->value = val;
+
+end:
+ return BT_OBJECT_FROM_CONCRETE(integer_obj);
+}
+
+struct bt_object *bt_object_integer_create(void)
+{
+ return bt_object_integer_create_init(0);
+}
+
+struct bt_object *bt_object_float_create_init(double val)
+{
+ struct bt_object_float *float_obj;
+
+ float_obj = g_new0(struct bt_object_float, 1);
+
+ if (!float_obj) {
+ goto end;
+ }
+
+ float_obj->base = bt_object_create_base(BT_OBJECT_TYPE_FLOAT);
+ float_obj->value = val;
+
+end:
+ return BT_OBJECT_FROM_CONCRETE(float_obj);
+}
+
+struct bt_object *bt_object_float_create(void)
+{
+ return bt_object_float_create_init(0.);
+}
+
+struct bt_object *bt_object_string_create_init(const char *val)
+{
+ struct bt_object_string *string_obj = NULL;
+
+ if (!val) {
+ goto end;
+ }
+
+ string_obj = g_new0(struct bt_object_string, 1);
+
+ if (!string_obj) {
+ goto end;
+ }
+
+ string_obj->base = bt_object_create_base(BT_OBJECT_TYPE_STRING);
+ string_obj->gstr = g_string_new(val);
+
+ if (!string_obj->gstr) {
+ g_free(string_obj);
+ string_obj = NULL;
+ goto end;
+ }
+
+end:
+ return BT_OBJECT_FROM_CONCRETE(string_obj);
+}
+
+struct bt_object *bt_object_string_create(void)
+{
+ return bt_object_string_create_init("");
+}
+
+struct bt_object *bt_object_array_create(void)
+{
+ struct bt_object_array *array_obj;
+
+ array_obj = g_new0(struct bt_object_array, 1);
+
+ if (!array_obj) {
+ goto end;
+ }
+
+ array_obj->base = bt_object_create_base(BT_OBJECT_TYPE_ARRAY);
+ array_obj->garray = g_array_new(FALSE, FALSE,
+ sizeof(struct bt_object *));
+
+ if (!array_obj->garray) {
+ g_free(array_obj);
+ array_obj = NULL;
+ goto end;
+ }
+
+end:
+ return BT_OBJECT_FROM_CONCRETE(array_obj);
+}
+
+struct bt_object *bt_object_map_create(void)
+{
+ struct bt_object_map *map_obj;
+
+ map_obj = g_new0(struct bt_object_map, 1);
+
+ if (!map_obj) {
+ goto end;
+ }
+
+ map_obj->base = bt_object_create_base(BT_OBJECT_TYPE_MAP);
+ map_obj->ght = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+ NULL, (GDestroyNotify) bt_object_put);
+
+ if (!map_obj->ght) {
+ g_free(map_obj);
+ map_obj = NULL;
+ goto end;
+ }
+
+end:
+ return BT_OBJECT_FROM_CONCRETE(map_obj);
+}
+
+int bt_object_bool_get(const struct bt_object *bool_obj, bool *val)
+{
+ int ret = 0;
+ struct bt_object_bool *typed_bool_obj = BT_OBJECT_TO_BOOL(bool_obj);
+
+ if (!bool_obj || !bt_object_is_bool(bool_obj)) {
+ ret = -1;
+ goto end;
+ }
+
+ *val = typed_bool_obj->value;
+
+end:
+ return ret;
+}
+
+int bt_object_bool_set(struct bt_object *bool_obj, bool val)
+{
+ int ret = 0;
+ struct bt_object_bool *typed_bool_obj = BT_OBJECT_TO_BOOL(bool_obj);
+
+ if (!bool_obj || !bt_object_is_bool(bool_obj)) {
+ ret = -1;
+ goto end;
+ }
+
+ typed_bool_obj->value = val;
+
+end:
+ return ret;
+}
+
+int bt_object_integer_get(const struct bt_object *integer_obj, int64_t *val)
+{
+ int ret = 0;
+ struct bt_object_integer *typed_integer_obj =
+ BT_OBJECT_TO_INTEGER(integer_obj);
+
+ if (!integer_obj || !bt_object_is_integer(integer_obj)) {
+ ret = -1;
+ goto end;
+ }
+
+ *val = typed_integer_obj->value;
+
+end:
+ return ret;
+}
+
+int bt_object_integer_set(struct bt_object *integer_obj, int64_t val)
+{
+ int ret = 0;
+ struct bt_object_integer *typed_integer_obj =
+ BT_OBJECT_TO_INTEGER(integer_obj);
+
+ if (!integer_obj || !bt_object_is_integer(integer_obj)) {
+ ret = -1;
+ goto end;
+ }
+
+ typed_integer_obj->value = val;
+
+end:
+ return ret;
+}
+
+int bt_object_float_get(const struct bt_object *float_obj, double *val)
+{
+ int ret = 0;
+ struct bt_object_float *typed_float_obj =
+ BT_OBJECT_TO_FLOAT(float_obj);
+
+ if (!float_obj || !bt_object_is_float(float_obj)) {
+ ret = -1;
+ goto end;
+ }
+
+ *val = typed_float_obj->value;
+
+end:
+ return ret;
+}
+
+int bt_object_float_set(struct bt_object *float_obj, double val)
+{
+ int ret = 0;
+ struct bt_object_float *typed_float_obj =
+ BT_OBJECT_TO_FLOAT(float_obj);
+
+ if (!float_obj || !bt_object_is_float(float_obj)) {
+ ret = -1;
+ goto end;
+ }
+
+ typed_float_obj->value = val;
+
+end:
+ return ret;
+}
+
+const char *bt_object_string_get(const struct bt_object *string_obj)
+{
+ const char *ret;
+ struct bt_object_string *typed_string_obj =
+ BT_OBJECT_TO_STRING(string_obj);
+
+ if (!string_obj || !bt_object_is_string(string_obj)) {
+ ret = NULL;
+ goto end;
+ }
+
+ ret = typed_string_obj->gstr->str;
+
+end:
+ return ret;
+}
+
+int bt_object_string_set(struct bt_object *string_obj, const char *val)
+{
+ int ret = 0;
+ struct bt_object_string *typed_string_obj =
+ BT_OBJECT_TO_STRING(string_obj);
+
+ if (!string_obj || !bt_object_is_string(string_obj) || !val) {
+ ret = -1;
+ goto end;
+ }
+
+ g_string_assign(typed_string_obj->gstr, val);
+
+end:
+ return ret;
+}
+
+int bt_object_array_size(const struct bt_object *array_obj)
+{
+ int ret = 0;
+ struct bt_object_array *typed_array_obj =
+ BT_OBJECT_TO_ARRAY(array_obj);
+
+ if (!array_obj || !bt_object_is_array(array_obj)) {
+ ret = -1;
+ goto end;
+ }
+
+ ret = (int) typed_array_obj->garray->len;
+
+end:
+ return ret;
+}
+
+bool bt_object_array_is_empty(const struct bt_object *array_obj)
+{
+ return bt_object_array_size(array_obj) == 0;
+}
+
+struct bt_object *bt_object_array_get(const struct bt_object *array_obj,
+ size_t index)
+{
+ struct bt_object *ret;
+ struct bt_object_array *typed_array_obj =
+ BT_OBJECT_TO_ARRAY(array_obj);
+
+ if (!array_obj || !bt_object_is_array(array_obj) ||
+ index >= typed_array_obj->garray->len) {
+ ret = NULL;
+ goto end;
+ }
+
+ ret = g_array_index(typed_array_obj->garray,
+ struct bt_object *, index);
+ bt_object_get(ret);
+
+end:
+ return ret;
+}
+
+int bt_object_array_append(struct bt_object *array_obj,
+ struct bt_object *element_obj)
+{
+ int ret = 0;
+ struct bt_object_array *typed_array_obj =
+ BT_OBJECT_TO_ARRAY(array_obj);
+
+ if (!array_obj || !bt_object_is_array(array_obj) || !element_obj) {
+ ret = -1;
+ goto end;
+ }
+
+ g_array_append_val(typed_array_obj->garray, element_obj);
+ bt_object_get(element_obj);
+
+end:
+ return ret;
+}
+
+int bt_object_array_append_bool(struct bt_object *array_obj, bool val)
+{
+ int ret;
+ struct bt_object *bool_obj = NULL;
+
+ bool_obj = bt_object_bool_create_init(val);
+ ret = bt_object_array_append(array_obj, bool_obj);
+ bt_object_put(bool_obj);
+
+ return ret;
+}
+
+int bt_object_array_append_integer(struct bt_object *array_obj, int64_t val)
+{
+ int ret;
+ struct bt_object *integer_obj = NULL;
+
+ integer_obj = bt_object_integer_create_init(val);
+ ret = bt_object_array_append(array_obj, integer_obj);
+ bt_object_put(integer_obj);
+
+ return ret;
+}
+
+int bt_object_array_append_float(struct bt_object *array_obj, double val)
+{
+ int ret;
+ struct bt_object *float_obj = NULL;
+
+ float_obj = bt_object_float_create_init(val);
+ ret = bt_object_array_append(array_obj, float_obj);
+ bt_object_put(float_obj);
+
+ return ret;
+}
+
+int bt_object_array_append_string(struct bt_object *array_obj, const char *val)
+{
+ int ret;
+ struct bt_object *string_obj = NULL;
+
+ string_obj = bt_object_string_create_init(val);
+ ret = bt_object_array_append(array_obj, string_obj);
+ bt_object_put(string_obj);
+
+ return ret;
+}
+
+int bt_object_array_append_array(struct bt_object *array_obj)
+{
+ int ret;
+ struct bt_object *empty_array_obj = NULL;
+
+ empty_array_obj = bt_object_array_create();
+ ret = bt_object_array_append(array_obj, empty_array_obj);
+ bt_object_put(empty_array_obj);
+
+ return ret;
+}
+
+int bt_object_array_append_map(struct bt_object *array_obj)
+{
+ int ret;
+ struct bt_object *map_obj = NULL;
+
+ map_obj = bt_object_map_create();
+ ret = bt_object_array_append(array_obj, map_obj);
+ bt_object_put(map_obj);
+
+ return ret;
+}
+
+int bt_object_map_size(const struct bt_object *map_obj)
+{
+ int ret;
+ struct bt_object_map *typed_map_obj = BT_OBJECT_TO_MAP(map_obj);
+
+ if (!map_obj || !bt_object_is_map(map_obj)) {
+ ret = -1;
+ goto end;
+ }
+
+ ret = (int) g_hash_table_size(typed_map_obj->ght);
+
+end:
+ return ret;
+}
+
+bool bt_object_map_is_empty(const struct bt_object *map_obj)
+{
+ return bt_object_map_size(map_obj) == 0;
+}
+
+struct bt_object *bt_object_map_get(const struct bt_object *map_obj,
+ const char *key)
+{
+ GQuark quark;
+ struct bt_object *ret;
+ struct bt_object_map *typed_map_obj = BT_OBJECT_TO_MAP(map_obj);
+
+ if (!map_obj || !bt_object_is_map(map_obj) || !key) {
+ ret = NULL;
+ goto end;
+ }
+
+ quark = g_quark_from_string(key);
+ ret = g_hash_table_lookup(typed_map_obj->ght, GUINT_TO_POINTER(quark));
+
+ if (ret) {
+ bt_object_get(ret);
+ }
+
+end:
+ return ret;
+}
+
+bool bt_object_map_has_key(const struct bt_object *map_obj, const char *key)
+{
+ bool ret;
+ GQuark quark;
+ struct bt_object_map *typed_map_obj = BT_OBJECT_TO_MAP(map_obj);
+
+ if (!map_obj || !bt_object_is_map(map_obj) || !key) {
+ ret = false;
+ goto end;
+ }
+
+ quark = g_quark_from_string(key);
+ ret = g_hash_table_contains(typed_map_obj->ght,
+ GUINT_TO_POINTER(quark));
+
+end:
+ return ret;
+}
+
+int bt_object_map_insert(struct bt_object *map_obj, const char *key,
+ struct bt_object *element_obj)
+{
+ int ret = 0;
+ GQuark quark;
+ struct bt_object_map *typed_map_obj = BT_OBJECT_TO_MAP(map_obj);
+
+ if (!map_obj || !bt_object_is_map(map_obj) || !key || !element_obj) {
+ ret = -1;
+ goto end;
+ }
+
+ quark = g_quark_from_string(key);
+ g_hash_table_insert(typed_map_obj->ght,
+ GUINT_TO_POINTER(quark), element_obj);
+ bt_object_get(element_obj);
+
+end:
+ return ret;
+}
+
+int bt_object_map_insert_bool(struct bt_object *map_obj,
+ const char *key, bool val)
+{
+ int ret;
+ struct bt_object *bool_obj = NULL;
+
+ bool_obj = bt_object_bool_create_init(val);
+ ret = bt_object_map_insert(map_obj, key, bool_obj);
+ bt_object_put(bool_obj);
+
+ return ret;
+}
+
+int bt_object_map_insert_integer(struct bt_object *map_obj,
+ const char *key, int64_t val)
+{
+ int ret;
+ struct bt_object *integer_obj = NULL;
+
+ integer_obj = bt_object_integer_create_init(val);
+ ret = bt_object_map_insert(map_obj, key, integer_obj);
+ bt_object_put(integer_obj);
+
+ return ret;
+}
+
+int bt_object_map_insert_float(struct bt_object *map_obj,
+ const char *key, double val)
+{
+ int ret;
+ struct bt_object *float_obj = NULL;
+
+ float_obj = bt_object_float_create_init(val);
+ ret = bt_object_map_insert(map_obj, key, float_obj);
+ bt_object_put(float_obj);
+
+ return ret;
+}
+
+int bt_object_map_insert_string(struct bt_object *map_obj,
+ const char *key, const char *val)
+{
+ int ret;
+ struct bt_object *string_obj = NULL;
+
+ string_obj = bt_object_string_create_init(val);
+ ret = bt_object_map_insert(map_obj, key, string_obj);
+ bt_object_put(string_obj);
+
+ return ret;
+}
+
+int bt_object_map_insert_array(struct bt_object *map_obj,
+ const char *key)
+{
+ int ret;
+ struct bt_object *array_obj = NULL;
+
+ array_obj = bt_object_array_create();
+ ret = bt_object_map_insert(map_obj, key, array_obj);
+ bt_object_put(array_obj);
+
+ return ret;
+}
+
+int bt_object_map_insert_map(struct bt_object *map_obj,
+ const char *key)
+{
+ int ret;
+ struct bt_object *empty_map_obj = NULL;
+
+ empty_map_obj = bt_object_map_create();
+ ret = bt_object_map_insert(map_obj, key, empty_map_obj);
+ bt_object_put(empty_map_obj);
+
+ return ret;
+}
+
+int bt_object_map_foreach(const struct bt_object *map_obj,
+ bt_object_map_foreach_cb cb, void *data)
+{
+ int ret = 0;
+ gpointer key, element_obj;
+ GHashTableIter iter;
+ struct bt_object_map *typed_map_obj = BT_OBJECT_TO_MAP(map_obj);
+
+ if (!map_obj || !bt_object_is_map(map_obj) || !cb) {
+ ret = -1;
+ goto end;
+ }
+
+ g_hash_table_iter_init(&iter, typed_map_obj->ght);
+
+ while (g_hash_table_iter_next(&iter, &key, &element_obj)) {
+ const char *key_str = g_quark_to_string((unsigned long) key);
+
+ if (!cb(key_str, element_obj, data)) {
+ break;
+ }
+ }
+
+end:
+ return ret;
+}
+
+struct bt_object *bt_object_copy(const struct bt_object *object)
+{
+ struct bt_object *copy_obj = NULL;
+
+ if (!object) {
+ goto end;
+ }
+
+ copy_obj = copy_funcs[object->type](object);
+
+end:
+ return copy_obj;
+}
+
+bool bt_object_compare(const struct bt_object *object_a,
+ const struct bt_object *object_b)
+{
+ bool ret = false;
+
+ if (!object_a || !object_b) {
+ goto end;
+ }
+
+ if (object_a->type != object_b->type) {
+ goto end;
+ }
+
+ ret = compare_funcs[object_a->type](object_a, object_b);
+
+end:
+ return ret;
+}