From 347829f5b1eaf79a540f4623f7ae5ee4e9e3d4c7 Mon Sep 17 00:00:00 2001 From: Philippe Proulx Date: Thu, 12 Mar 2015 16:14:31 -0400 Subject: [PATCH] Add basic object system MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Proulx Signed-off-by: Jérémie Galarneau --- include/Makefile.am | 3 +- include/babeltrace/objects.h | 878 +++++++++++++++++++++++++++ lib/Makefile.am | 3 +- lib/objects.c | 1092 ++++++++++++++++++++++++++++++++++ 4 files changed, 1974 insertions(+), 2 deletions(-) create mode 100644 include/babeltrace/objects.h create mode 100644 lib/objects.c diff --git a/include/Makefile.am b/include/Makefile.am index 9f106c96..2928f757 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -5,7 +5,8 @@ babeltraceinclude_HEADERS = \ babeltrace/iterator.h \ babeltrace/trace-handle.h \ babeltrace/list.h \ - babeltrace/clock-types.h + babeltrace/clock-types.h \ + babeltrace/objects.h babeltracectfinclude_HEADERS = \ babeltrace/ctf/events.h \ diff --git a/include/babeltrace/objects.h b/include/babeltrace/objects.h new file mode 100644 index 00000000..3b66cecb --- /dev/null +++ b/include/babeltrace/objects.h @@ -0,0 +1,878 @@ +#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 + * + * 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 + * @bug No known bugs + */ + +#include +#include +#include + +#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 + * BT_OBJECT_TYPE_NULL\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 not changed. 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 + * BT_OBJECT_TYPE_UNKNOWN\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 weak reference: + * 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 */ diff --git a/lib/Makefile.am b/lib/Makefile.am index 348b0a9b..8fe87f34 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -9,7 +9,8 @@ libbabeltrace_la_SOURCES = babeltrace.c \ context.c \ trace-handle.c \ trace-collection.c \ - registry.c + registry.c \ + objects.c libbabeltrace_la_LDFLAGS = -version-info $(BABELTRACE_LIBRARY_VERSION) diff --git a/lib/objects.c b/lib/objects.c new file mode 100644 index 00000000..7fb34841 --- /dev/null +++ b/lib/objects.c @@ -0,0 +1,1092 @@ +/* + * objects.c: basic object system + * + * Babeltrace Library + * + * Copyright (c) 2015 EfficiOS Inc. and Linux Foundation + * Copyright (c) 2015 Philippe Proulx + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#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; +} -- 2.34.1