}
#undef EINA_VALUE_TYPE_LIST_CHECK_RETURN_VAL
+#define EINA_VALUE_TYPE_HASH_CHECK_RETURN_VAL(value, retval) \
+ EINA_SAFETY_ON_NULL_RETURN_VAL(value, retval); \
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(value->type == EINA_VALUE_TYPE_HASH, retval)
+
+static inline Eina_Bool
+eina_value_hash_setup(Eina_Value *value, const Eina_Value_Type *subtype, unsigned int buckets_power_size)
+{
+ Eina_Value_Hash desc = { subtype, buckets_power_size, NULL };
+ if (!eina_value_setup(value, EINA_VALUE_TYPE_HASH))
+ return EINA_FALSE;
+ if (!eina_value_pset(value, &desc))
+ {
+ eina_value_flush(value);
+ return EINA_FALSE;
+ }
+ return EINA_TRUE;
+}
+
+static inline unsigned int
+eina_value_hash_population(const Eina_Value *value)
+{
+ Eina_Value_Hash *desc;
+ EINA_VALUE_TYPE_HASH_CHECK_RETURN_VAL(value, 0);
+ desc = eina_value_memory_get(value);
+ if (!desc)
+ return 0;
+ return eina_hash_population(desc->hash);
+}
+
+static inline Eina_Bool
+eina_value_hash_del(Eina_Value *value, const char *key)
+{
+ Eina_Value_Hash *desc;
+ void *mem;
+
+ EINA_VALUE_TYPE_HASH_CHECK_RETURN_VAL(value, EINA_FALSE);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(key, EINA_FALSE);
+ desc = eina_value_memory_get(value);
+ if (!desc)
+ return EINA_FALSE;
+
+ mem = eina_hash_find(desc->hash, key);
+ if (!mem)
+ return EINA_FALSE;
+
+ eina_value_type_flush(desc->subtype, mem);
+ free(mem);
+ eina_hash_del_by_key(desc->hash, key);
+ return EINA_TRUE;
+}
+
+static inline Eina_Bool
+eina_value_hash_vset(Eina_Value *value, const char *key, va_list args)
+{
+ Eina_Value_Hash *desc;
+ void *mem;
+
+ EINA_VALUE_TYPE_HASH_CHECK_RETURN_VAL(value, EINA_FALSE);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(key, EINA_FALSE);
+ desc = eina_value_memory_get(value);
+ if (!desc)
+ return EINA_FALSE;
+
+ mem = eina_hash_find(desc->hash, key);
+ if (mem)
+ eina_value_type_flush(desc->subtype, mem);
+ else
+ {
+ mem = malloc(desc->subtype->value_size);
+ if (!mem)
+ {
+ eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
+ return EINA_FALSE;
+ }
+ if (!eina_hash_add(desc->hash, key, mem))
+ {
+ free(mem);
+ return EINA_FALSE;
+ }
+ }
+
+ if (!eina_value_type_setup(desc->subtype, mem)) goto error_setup;
+ if (!eina_value_type_vset(desc->subtype, mem, args)) goto error_set;
+ return EINA_TRUE;
+
+ error_set:
+ eina_value_type_flush(desc->subtype, mem);
+ error_setup:
+ eina_hash_del_by_key(desc->hash, key);
+ free(mem);
+ return EINA_FALSE;
+}
+
+static inline Eina_Bool
+eina_value_hash_vget(const Eina_Value *value, const char *key, va_list args)
+{
+ Eina_Value_Hash *desc;
+ const void *mem;
+ void *ptr;
+ Eina_Bool ret;
+
+ EINA_VALUE_TYPE_HASH_CHECK_RETURN_VAL(value, EINA_FALSE);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(key, EINA_FALSE);
+ desc = eina_value_memory_get(value);
+ if (!desc)
+ return EINA_FALSE;
+
+ mem = eina_hash_find(desc->hash, key);
+ if (!mem)
+ return EINA_FALSE;
+
+ ptr = va_arg(args, void *);
+ ret = eina_value_type_pget(desc->subtype, mem, ptr);
+ return ret;
+}
+
+static inline Eina_Bool
+eina_value_hash_set(Eina_Value *value, const char *key, ...)
+{
+ va_list args;
+ Eina_Bool ret;
+ va_start(args, key);
+ ret = eina_value_hash_vset(value, key, args);
+ va_end(args);
+ return ret;
+}
+
+static inline Eina_Bool
+eina_value_hash_get(const Eina_Value *value, const char *key, ...)
+{
+ va_list args;
+ Eina_Bool ret;
+ va_start(args, key);
+ ret = eina_value_hash_vget(value, key, args);
+ va_end(args);
+ return ret;
+}
+
+static inline Eina_Bool
+eina_value_hash_pset(Eina_Value *value, const char *key, const void *ptr)
+{
+ Eina_Value_Hash *desc;
+ void *mem;
+
+ EINA_VALUE_TYPE_HASH_CHECK_RETURN_VAL(value, 0);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(key, EINA_FALSE);
+ desc = eina_value_memory_get(value);
+ if (!desc)
+ return EINA_FALSE;
+
+ mem = eina_hash_find(desc->hash, key);
+ if (mem)
+ eina_value_type_flush(desc->subtype, mem);
+ else
+ {
+ mem = malloc(desc->subtype->value_size);
+ if (!mem)
+ {
+ eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
+ return EINA_FALSE;
+ }
+ if (!eina_hash_add(desc->hash, key, mem))
+ {
+ free(mem);
+ return EINA_FALSE;
+ }
+ }
+
+ if (!eina_value_type_setup(desc->subtype, mem)) goto error_setup;
+ if (!eina_value_type_pset(desc->subtype, mem, ptr)) goto error_set;
+ return EINA_TRUE;
+
+ error_set:
+ eina_value_type_flush(desc->subtype, mem);
+ error_setup:
+ eina_hash_del_by_key(desc->hash, key);
+ free(mem);
+ return EINA_FALSE;
+}
+
+static inline Eina_Bool
+eina_value_hash_pget(const Eina_Value *value, const char *key, void *ptr)
+{
+ Eina_Value_Hash *desc;
+ const void *mem;
+ Eina_Bool ret;
+
+ EINA_VALUE_TYPE_HASH_CHECK_RETURN_VAL(value, 0);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(key, EINA_FALSE);
+ desc = eina_value_memory_get(value);
+ if (!desc)
+ return EINA_FALSE;
+
+ mem = eina_hash_find(desc->hash, key);
+ if (!mem)
+ return EINA_FALSE;
+
+ ret = eina_value_type_pget(desc->subtype, mem, ptr);
+ return ret;
+}
+#undef EINA_VALUE_TYPE_HASH_CHECK_RETURN_VAL
+
static inline Eina_Bool
eina_value_type_setup(const Eina_Value_Type *type, void *mem)
#include "eina_fp.h" /* defines int64_t and uint64_t */
#include "eina_inarray.h"
#include "eina_list.h"
+#include "eina_hash.h"
#include <stdarg.h>
/**
*/
EAPI extern const Eina_Value_Type *EINA_VALUE_TYPE_LIST;
+/**
+ * @var EINA_VALUE_TYPE_HASH
+ *
+ * manages hash type. The value get/set are the type of elements in
+ * the hash, use the alternaties:
+ * @li eina_value_hash_get() and eina_value_hash_set()
+ * @li eina_value_hash_vget() and eina_value_hash_vset()
+ * @li eina_value_hash_pget() and eina_value_hash_pset()
+ *
+ * @since 1.2
+ */
+EAPI extern const Eina_Value_Type *EINA_VALUE_TYPE_HASH;
+
/**
* @var EINA_ERROR_VALUE_FAILED
* @li EINA_VALUE_TYPE_STRING: const char *
* @li EINA_VALUE_TYPE_ARRAY: Eina_Value_Array
* @li EINA_VALUE_TYPE_LIST: Eina_Value_List
+ * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash
*
* @code
* Eina_Value *value = eina_value_new(EINA_VALUE_TYPE_INT);
*
* @note for array member see eina_value_array_set()
* @note for list member see eina_value_list_set()
+ * @note for hash member see eina_value_hash_set()
*
* @see eina_value_get()
* @see eina_value_vset()
* @li EINA_VALUE_TYPE_STRING: const char **
* @li EINA_VALUE_TYPE_ARRAY: Eina_Value_Array*
* @li EINA_VALUE_TYPE_LIST: Eina_Value_List*
+ * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash*
*
* @code
* Eina_Value *value = eina_value_new(EINA_VALUE_TYPE_INT);
*
* @note for array member see eina_value_array_get()
* @note for list member see eina_value_list_get()
+ * @note for hash member see eina_value_hash_get()
*
* @see eina_value_set()
* @see eina_value_vset()
*
* @note for array member see eina_value_array_vset()
* @note for list member see eina_value_list_vset()
+ * @note for hash member see eina_value_hash_vset()
*
* @see eina_value_vget()
* @see eina_value_set()
*
* @note for array member see eina_value_array_vget()
* @note for list member see eina_value_list_vget()
+ * @note for hash member see eina_value_hash_vget()
*
* @see eina_value_vset()
* @see eina_value_get()
* @li EINA_VALUE_TYPE_STRING: const char **
* @li EINA_VALUE_TYPE_ARRAY: Eina_Value_Array*
* @li EINA_VALUE_TYPE_LIST: Eina_Value_List*
+ * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash*
*
* @note the pointer contents are written using the size defined by
* type. It can be larger than void* or uint64_t.
*
* @note for array member see eina_value_array_pset()
* @note for list member see eina_value_list_pset()
+ * @note for hash member see eina_value_hash_pset()
*
* @see eina_value_pget()
* @see eina_value_set()
* @li EINA_VALUE_TYPE_STRING: const char **
* @li EINA_VALUE_TYPE_ARRAY: Eina_Value_Array*
* @li EINA_VALUE_TYPE_LIST: Eina_Value_List*
+ * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash*
*
* @code
* Eina_Value *value = eina_value_new(EINA_VALUE_TYPE_INT);
*
* @note for array member see eina_value_array_get()
* @note for list member see eina_value_list_get()
+ * @note for hash member see eina_value_hash_get()
*
* @see eina_value_set()
* @see eina_value_vset()
* @li EINA_VALUE_TYPE_STRINGSHARE: const char *
* @li EINA_VALUE_TYPE_STRING: const char *
* @li EINA_VALUE_TYPE_ARRAY: Eina_Value_Array
+ * @li EINA_VALUE_TYPE_LIST: Eina_Value_List
+ * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash
*
* @code
- * Eina_Value *value = eina_value_array_new(EINA_VALUE_TYPE_INT);
+ * Eina_Value *value = eina_value_array_new(EINA_VALUE_TYPE_INT, 0);
* int x;
*
* eina_value_array_append(value, 1234);
* @li EINA_VALUE_TYPE_STRINGSHARE: const char **
* @li EINA_VALUE_TYPE_STRING: const char **
* @li EINA_VALUE_TYPE_ARRAY: Eina_Value_Array*
+ * @li EINA_VALUE_TYPE_LIST: Eina_Value_List*
+ * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash*
*
* @code
- * Eina_Value *value = eina_value_array_new(EINA_VALUE_TYPE_INT);
+ * Eina_Value *value = eina_value_array_new(EINA_VALUE_TYPE_INT, 0);
* int x;
*
* eina_value_array_append(value, 1234);
* @li EINA_VALUE_TYPE_STRINGSHARE: const char *
* @li EINA_VALUE_TYPE_STRING: const char *
* @li EINA_VALUE_TYPE_ARRAY: Eina_Value_Array
+ * @li EINA_VALUE_TYPE_LIST: Eina_Value_List
+ * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash
*
* @code
- * Eina_Value *value = eina_value_array_new(EINA_VALUE_TYPE_INT);
+ * Eina_Value *value = eina_value_array_new(EINA_VALUE_TYPE_INT, 0);
* int x;
*
* eina_value_array_insert(value, 0, 1234);
* @li EINA_VALUE_TYPE_STRINGSHARE: const char *
* @li EINA_VALUE_TYPE_STRING: const char *
* @li EINA_VALUE_TYPE_ARRAY: Eina_Value_Array
+ * @li EINA_VALUE_TYPE_LIST: Eina_Value_List
+ * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash
*
* @code
- * Eina_Value *value = eina_value_array_new(EINA_VALUE_TYPE_INT);
+ * Eina_Value *value = eina_value_array_new(EINA_VALUE_TYPE_INT, 0);
* int x;
*
* eina_value_array_append(value, 1234);
* @li EINA_VALUE_TYPE_STRINGSHARE: const char **
* @li EINA_VALUE_TYPE_STRING: const char **
* @li EINA_VALUE_TYPE_ARRAY: Eina_Value_Array*
+ * @li EINA_VALUE_TYPE_LIST: Eina_Value_List
+ * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash
*
* @note the pointer contents are written using the size defined by
* type. It can be larger than void* or uint64_t.
*
* @code
- * Eina_Value *value = eina_value_array_new(EINA_VALUE_TYPE_INT);
+ * Eina_Value *value = eina_value_array_new(EINA_VALUE_TYPE_INT, 0);
* int x = 1234;
*
* eina_value_array_append(value, 1234);
* @li EINA_VALUE_TYPE_STRINGSHARE: const char **
* @li EINA_VALUE_TYPE_STRING: const char **
* @li EINA_VALUE_TYPE_ARRAY: Eina_Value_Array*
+ * @li EINA_VALUE_TYPE_LIST: Eina_Value_List
+ * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash
*
* @code
- * Eina_Value *value = eina_value_array_new(EINA_VALUE_TYPE_INT);
+ * Eina_Value *value = eina_value_array_new(EINA_VALUE_TYPE_INT, 0);
* int x;
*
* eina_value_array_append(value, 1234);
* @li EINA_VALUE_TYPE_STRINGSHARE: const char **
* @li EINA_VALUE_TYPE_STRING: const char **
* @li EINA_VALUE_TYPE_ARRAY: Eina_Value_Array*
+ * @li EINA_VALUE_TYPE_LIST: Eina_Value_List
+ * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash
*
* @note the pointer contents are written using the size defined by
* type. It can be larger than void* or uint64_t.
*
* @code
- * Eina_Value *value = eina_value_array_new(EINA_VALUE_TYPE_INT);
+ * Eina_Value *value = eina_value_array_new(EINA_VALUE_TYPE_INT, 0);
* int x = 1234;
*
* eina_value_array_pinsert(value, 0, &x);
* @li EINA_VALUE_TYPE_STRINGSHARE: const char **
* @li EINA_VALUE_TYPE_STRING: const char **
* @li EINA_VALUE_TYPE_ARRAY: Eina_Value_Array*
+ * @li EINA_VALUE_TYPE_LIST: Eina_Value_List
+ * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash
*
* @note the pointer contents are written using the size defined by
* type. It can be larger than void* or uint64_t.
*
* @code
- * Eina_Value *value = eina_value_array_new(EINA_VALUE_TYPE_INT);
+ * Eina_Value *value = eina_value_array_new(EINA_VALUE_TYPE_INT, 0);
* int x = 1234;
*
* eina_value_array_pappend(value, &x);
*/
/**
+ * @defgroup Eina_Value_Hash_Group Generic Value Hash management
+ *
+ * @{
+ */
+
+/**
+ * @typedef Eina_Value_Hash
+ * Value type for #EINA_VALUE_TYPE_HASH
+ *
+ * @since 1.2
+ */
+typedef struct _Eina_Value_Hash Eina_Value_Hash;
+
+/**
+ * @struct _Eina_Value_Hash
+ * Used to store the hash and its subtype.
+ */
+struct _Eina_Value_Hash
+{
+ const Eina_Value_Type *subtype; /**< how to allocate and access items */
+ unsigned int buckets_power_size; /**< how to allocate hash buckets, if zero a sane default is chosen. */
+ Eina_Hash *hash; /**< the hash that holds data, members are of subtype->value_size bytes. */
+};
+
+/**
+ * @brief Create generic value storage of type hash.
+ * @param subtype how to manage this hash members.
+ * @param buckets_power_size how to allocate hash buckets (2 ^
+ * buckets_power_size), if zero then a sane value is chosen.
+ * @return The new value or @c NULL on failure.
+ *
+ * Create a new generic value storage of type hash. The members are
+ * managed using the description specified by @a subtype.
+ *
+ * On failure, @c NULL is returned and #EINA_ERROR_OUT_OF_MEMORY or
+ * #EINA_ERROR_VALUE_FAILED is set.
+ *
+ * @note this is a helper around eina_value_hash_setup() doing malloc
+ * for you.
+ *
+ * @see eina_value_free()
+ * @see eina_value_hash_setup()
+ *
+ * @since 1.2
+ */
+EAPI Eina_Value *eina_value_hash_new(const Eina_Value_Type *subtype, unsigned int buckets_power_size) EINA_ARG_NONNULL(1);
+
+/**
+ * @brief Setup generic value storage of type hash.
+ * @param value value object
+ * @param subtype how to manage this hash members.
+ * @param buckets_power_size how to allocate hash buckets (2 ^
+ * buckets_power_size), if zero then a sane value is chosen.
+ * @return #EINA_TRUE on success, #EINA_FALSE otherwise.
+ *
+ * Setups new generic value storage of type hash with the given
+ * @a subtype.
+ *
+ * This is the same as calling eina_value_set() with
+ * #EINA_VALUE_TYPE_HASH followed by eina_value_pset() with the
+ * #Eina_Value_Hash description configured.
+ *
+ * @note Existing memory is ignored! If it was previously set, then
+ * use eina_value_flush() first.
+ *
+ * On failure, #EINA_FALSE is returned and #EINA_ERROR_OUT_OF_MEMORY
+ * or #EINA_ERROR_VALUE_FAILED is set.
+ *
+ * @see eina_value_flush()
+ *
+ * @since 1.2
+ */
+static inline Eina_Bool eina_value_hash_setup(Eina_Value *value,
+ const Eina_Value_Type *subtype,
+ unsigned int buckets_power_size) EINA_ARG_NONNULL(1, 2);
+
+/**
+ * @brief Query number of elements in value of hash type.
+ * @param value value object.
+ * @return number of child elements.
+ * @since 1.2
+ */
+static inline unsigned int eina_value_hash_population(const Eina_Value *value);
+
+/**
+ * @brief Remove element at given position in value of hash type.
+ * @param value value object.
+ * @param key key to find the member
+ * @return #EINA_TRUE on success, #EINA_FALSE otherwise.
+ * @since 1.2
+ */
+static inline Eina_Bool eina_value_hash_del(Eina_Value *value,
+ const char *key) EINA_ARG_NONNULL(1);
+
+/**
+ * @brief Set the generic value in an hash member.
+ * @param value source value object
+ * @param key key to find the member
+ * @return #EINA_TRUE on success, #EINA_FALSE otherwise.
+ *
+ * The variable argument is dependent on chosen subtype. The hash for
+ * basic types:
+ *
+ * @li EINA_VALUE_TYPE_UCHAR: unsigned char
+ * @li EINA_VALUE_TYPE_USHORT: unsigned short
+ * @li EINA_VALUE_TYPE_UINT: unsigned int
+ * @li EINA_VALUE_TYPE_ULONG: unsigned long
+ * @li EINA_VALUE_TYPE_UINT64: uint64_t
+ * @li EINA_VALUE_TYPE_CHAR: char
+ * @li EINA_VALUE_TYPE_SHORT: short
+ * @li EINA_VALUE_TYPE_INT: int
+ * @li EINA_VALUE_TYPE_LONG: long
+ * @li EINA_VALUE_TYPE_INT64: int64_t
+ * @li EINA_VALUE_TYPE_FLOAT: float
+ * @li EINA_VALUE_TYPE_DOUBLE: double
+ * @li EINA_VALUE_TYPE_STRINGSHARE: const char *
+ * @li EINA_VALUE_TYPE_STRING: const char *
+ * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash
+ *
+ * @code
+ * Eina_Value *value = eina_value_hash_new(EINA_VALUE_TYPE_INT, 0);
+ * int x;
+ *
+ * eina_value_hash_set(value, "abc", 5678);
+ * eina_value_hash_get(value, "abc", &x);
+ * eina_value_free(value);
+ * @endcode
+ *
+ * @see eina_value_hash_get()
+ * @see eina_value_hash_vset()
+ * @see eina_value_hash_pset()
+ * @see eina_value_hash_del()
+ *
+ * @since 1.2
+ */
+static inline Eina_Bool eina_value_hash_set(Eina_Value *value,
+ const char *key,
+ ...) EINA_ARG_NONNULL(1);
+
+/**
+ * @brief Get the generic value from an hash member.
+ * @param value source value object
+ * @param key key to find the member
+ * @return #EINA_TRUE on success, #EINA_FALSE otherwise.
+ *
+ * The value is returned in the variable argument parameter, the
+ * actual value is type-dependent, but usually it will be what is
+ * stored inside the object. There shouldn't be any memory allocation,
+ * thus the contents should @b not be free'd.
+ *
+ * The variable argument is dependent on chosen subtype. The hash for
+ * basic types:
+ *
+ * @li EINA_VALUE_TYPE_UCHAR: unsigned char*
+ * @li EINA_VALUE_TYPE_USHORT: unsigned short*
+ * @li EINA_VALUE_TYPE_UINT: unsigned int*
+ * @li EINA_VALUE_TYPE_ULONG: unsigned long*
+ * @li EINA_VALUE_TYPE_UINT64: uint64_t*
+ * @li EINA_VALUE_TYPE_CHAR: char*
+ * @li EINA_VALUE_TYPE_SHORT: short*
+ * @li EINA_VALUE_TYPE_INT: int*
+ * @li EINA_VALUE_TYPE_LONG: long*
+ * @li EINA_VALUE_TYPE_INT64: int64_t*
+ * @li EINA_VALUE_TYPE_FLOAT: float*
+ * @li EINA_VALUE_TYPE_DOUBLE: double*
+ * @li EINA_VALUE_TYPE_STRINGSHARE: const char **
+ * @li EINA_VALUE_TYPE_STRING: const char **
+ * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash*
+ *
+ * @code
+ * Eina_Value *value = eina_value_hash_new(EINA_VALUE_TYPE_INT, 0);
+ * int x;
+ *
+ * eina_value_hash_set(value, "abc", 1234);
+ * eina_value_hash_get(value, "abc", &x);
+ * eina_value_free(value);
+ * @endcode
+ *
+ * @see eina_value_hash_set()
+ * @see eina_value_hash_vset()
+ * @see eina_value_hash_pset()
+ *
+ * @since 1.2
+ */
+static inline Eina_Bool eina_value_hash_get(const Eina_Value *value,
+ const char *key,
+ ...) EINA_ARG_NONNULL(1);
+
+/**
+ * @brief Set the generic value in an hash member.
+ * @param value source value object
+ * @param key key to find the member
+ * @param args variable argument
+ * @return #EINA_TRUE on success, #EINA_FALSE otherwise.
+ * @see eina_value_hash_set()
+ * @see eina_value_hash_get()
+ * @see eina_value_hash_pset()
+ *
+ * @since 1.2
+ */
+static inline Eina_Bool eina_value_hash_vset(Eina_Value *value,
+ const char *key,
+ va_list args) EINA_ARG_NONNULL(1);
+
+/**
+ * @brief Get the generic value from an hash member.
+ * @param value source value object
+ * @param key key to find the member
+ * @param args variable argument
+ * @return #EINA_TRUE on success, #EINA_FALSE otherwise.
+ *
+ * The value is returned in the variable argument parameter, the
+ * actual value is type-dependent, but usually it will be what is
+ * stored inside the object. There shouldn't be any memory allocation,
+ * thus the contents should @b not be free'd.
+ *
+ * @see eina_value_hash_vset()
+ * @see eina_value_hash_get()
+ * @see eina_value_hash_pget()
+ *
+ * @since 1.2
+ */
+static inline Eina_Bool eina_value_hash_vget(const Eina_Value *value,
+ const char *key,
+ va_list args) EINA_ARG_NONNULL(1);
+
+/**
+ * @brief Set the generic value in an hash member from pointer.
+ * @param value source value object
+ * @param key key to find the member
+ * @param ptr pointer to specify the contents.
+ * @return #EINA_TRUE on success, #EINA_FALSE otherwise.
+ *
+ * The pointer type is dependent on chosen value type. The hash for
+ * basic types:
+ *
+ * @li EINA_VALUE_TYPE_UCHAR: unsigned char*
+ * @li EINA_VALUE_TYPE_USHORT: unsigned short*
+ * @li EINA_VALUE_TYPE_UINT: unsigned int*
+ * @li EINA_VALUE_TYPE_ULONG: unsigned long*
+ * @li EINA_VALUE_TYPE_UINT64: uint64_t*
+ * @li EINA_VALUE_TYPE_CHAR: char*
+ * @li EINA_VALUE_TYPE_SHORT: short*
+ * @li EINA_VALUE_TYPE_INT: int*
+ * @li EINA_VALUE_TYPE_LONG: long*
+ * @li EINA_VALUE_TYPE_INT64: int64_t*
+ * @li EINA_VALUE_TYPE_FLOAT: float*
+ * @li EINA_VALUE_TYPE_DOUBLE: double*
+ * @li EINA_VALUE_TYPE_STRINGSHARE: const char **
+ * @li EINA_VALUE_TYPE_STRING: const char **
+ * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash*
+ *
+ * @note the pointer contents are written using the size defined by
+ * type. It can be larger than void* or uint64_t.
+ *
+ * @code
+ * Eina_Value *value = eina_value_hash_new(EINA_VALUE_TYPE_INT, 0);
+ * int x = 1234;
+ *
+ * eina_value_hash_pset(value, "abc", &x);
+ * eina_value_hash_pget(value, "abc", &x);
+ * eina_value_free(value);
+ * @endcode
+ *
+ * @see eina_value_hash_set()
+ * @see eina_value_hash_get()
+ * @see eina_value_hash_vset()
+ *
+ * @since 1.2
+ */
+static inline Eina_Bool eina_value_hash_pset(Eina_Value *value,
+ const char *key,
+ const void *ptr) EINA_ARG_NONNULL(1, 3);
+
+/**
+ * @brief Get the generic value to pointer from an hash member.
+ * @param value source value object
+ * @param key key to find the member
+ * @param ptr pointer to receive the contents.
+ * @return #EINA_TRUE on success, #EINA_FALSE otherwise.
+ *
+ * The value is returned in pointer contents, the actual value is
+ * type-dependent, but usually it will be what is stored inside the
+ * object. There shouldn't be any memory allocation, thus the contents
+ * should @b not be free'd.
+ *
+ * The pointer type is dependent on chosen value type. The hash for
+ * basic types:
+ *
+ * @li EINA_VALUE_TYPE_UCHAR: unsigned char*
+ * @li EINA_VALUE_TYPE_USHORT: unsigned short*
+ * @li EINA_VALUE_TYPE_UINT: unsigned int*
+ * @li EINA_VALUE_TYPE_ULONG: unsigned long*
+ * @li EINA_VALUE_TYPE_UINT64: uint64_t*
+ * @li EINA_VALUE_TYPE_CHAR: char*
+ * @li EINA_VALUE_TYPE_SHORT: short*
+ * @li EINA_VALUE_TYPE_INT: int*
+ * @li EINA_VALUE_TYPE_LONG: long*
+ * @li EINA_VALUE_TYPE_INT64: int64_t*
+ * @li EINA_VALUE_TYPE_FLOAT: float*
+ * @li EINA_VALUE_TYPE_DOUBLE: double*
+ * @li EINA_VALUE_TYPE_STRINGSHARE: const char **
+ * @li EINA_VALUE_TYPE_STRING: const char **
+ * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash*
+ *
+ * @code
+ * Eina_Value *value = eina_value_hash_new(EINA_VALUE_TYPE_INT, 0);
+ * int x;
+ *
+ * eina_value_hash_set(value, "abc", 1234);
+ * eina_value_hash_pget(value, "abc", &x);
+ * eina_value_free(value);
+ * @endcode
+ *
+ * @see eina_value_hash_set()
+ * @see eina_value_hash_vset()
+ * @see eina_value_hash_pset()
+ *
+ * @since 1.2
+ */
+static inline Eina_Bool eina_value_hash_pget(const Eina_Value *value,
+ const char *key,
+ void *ptr) EINA_ARG_NONNULL(1, 3);
+
+/**
+ * @}
+ */
+
+
+/**
* @defgroup Eina_Value_Type_Group Generic Value Type management
*
* @{
_eina_value_type_list_pget
};
+static Eina_Bool
+_eina_value_type_hash_setup(const Eina_Value_Type *type __UNUSED__, void *mem)
+{
+ memset(mem, 0, sizeof(Eina_Value_Hash));
+ return EINA_TRUE;
+}
+
+struct _eina_value_type_hash_flush_each_ctx
+{
+ const Eina_Value_Type *subtype;
+ Eina_Bool ret;
+};
+
+static Eina_Bool
+_eina_value_type_hash_flush_each(const Eina_Hash *hash __UNUSED__, const void *key __UNUSED__, void *mem, void *user_data)
+{
+ struct _eina_value_type_hash_flush_each_ctx *ctx = user_data;
+ ctx->ret &= eina_value_type_flush(ctx->subtype, mem);
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_eina_value_type_hash_flush_elements(Eina_Value_Hash *tmem)
+{
+ struct _eina_value_type_hash_flush_each_ctx ctx = {
+ tmem->subtype,
+ EINA_TRUE
+ };
+
+ if (!tmem->hash) return EINA_TRUE;
+
+ eina_hash_foreach(tmem->hash, _eina_value_type_hash_flush_each, &ctx);
+ eina_hash_free(tmem->hash);
+ tmem->hash = NULL;
+ return ctx.ret;
+}
+
+static Eina_Bool
+_eina_value_type_hash_flush(const Eina_Value_Type *type __UNUSED__, void *mem)
+{
+ Eina_Value_Hash *tmem = mem;
+ Eina_Bool ret =_eina_value_type_hash_flush_elements(tmem);
+ tmem->subtype = NULL;
+ return ret;
+}
+
+static unsigned int
+_eina_value_hash_key_length(const void *key)
+{
+ if (!key)
+ return 0;
+ return (int)strlen(key) + 1;
+}
+
+static int
+_eina_value_hash_key_cmp(const void *key1, int key1_len, const void *key2, int key2_len)
+{
+ int r = key1_len - key2_len;
+ if (r != 0)
+ return r;
+ return strcmp(key1, key2);
+}
+
+static Eina_Bool
+_eina_value_type_hash_create(Eina_Value_Hash *desc)
+{
+ if (!desc->buckets_power_size)
+ desc->buckets_power_size = 5;
+
+ desc->hash = eina_hash_new(_eina_value_hash_key_length,
+ _eina_value_hash_key_cmp,
+ EINA_KEY_HASH(eina_hash_superfast),
+ NULL, desc->buckets_power_size);
+ return !!desc->hash;
+}
+
+struct _eina_value_type_hash_copy_each_ctx
+{
+ const Eina_Value_Type *subtype;
+ Eina_Value_Hash *dest;
+ Eina_Bool ret;
+};
+
+static Eina_Bool
+_eina_value_type_hash_copy_each(const Eina_Hash *hash __UNUSED__, const void *key, void *_ptr, void *user_data)
+{
+ struct _eina_value_type_hash_copy_each_ctx *ctx = user_data;
+ const void *ptr = _ptr;
+ void *imem = malloc(ctx->subtype->value_size);
+ if (!imem)
+ {
+ ctx->ret = EINA_FALSE;
+ return EINA_FALSE;
+ }
+ if (!ctx->subtype->copy(ctx->subtype, ptr, imem))
+ {
+ free(imem);
+ ctx->ret = EINA_FALSE;
+ return EINA_FALSE;
+ }
+ if (!eina_hash_add(ctx->dest->hash, key, imem))
+ {
+ eina_value_type_flush(ctx->subtype, imem);
+ free(imem);
+ ctx->ret = EINA_FALSE;
+ return EINA_FALSE;
+ }
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_eina_value_type_hash_copy(const Eina_Value_Type *type __UNUSED__, const void *src, void *dst)
+{
+ const Eina_Value_Hash *s = src;
+ Eina_Value_Hash *d = dst;
+ struct _eina_value_type_hash_copy_each_ctx ctx = {s->subtype, d, EINA_TRUE};
+
+ d->subtype = s->subtype;
+ d->buckets_power_size = s->buckets_power_size;
+
+ if ((!s->hash) || (!s->subtype))
+ {
+ d->hash = NULL;
+ return EINA_TRUE;
+ }
+
+ if (!s->subtype->copy)
+ {
+ eina_error_set(EINA_ERROR_VALUE_FAILED);
+ return EINA_FALSE;
+ }
+
+ if (!_eina_value_type_hash_create(d))
+ return EINA_FALSE;
+
+ eina_hash_foreach(s->hash, _eina_value_type_hash_copy_each, &ctx);
+ if (!ctx.ret)
+ {
+ _eina_value_type_hash_flush_elements(d);
+ return EINA_FALSE;
+ }
+ return EINA_TRUE;
+}
+
+struct _eina_value_type_hash_compare_each_ctx
+{
+ const Eina_Value_Type *subtype;
+ const Eina_Hash *other;
+ int cmp;
+};
+
+static Eina_Bool
+_eina_value_type_hash_compare_each(const Eina_Hash *hash __UNUSED__, const void *key, void *_ptr, void *user_data)
+{
+ struct _eina_value_type_hash_compare_each_ctx *ctx = user_data;
+ const void *self_ptr = _ptr;
+ const void *other_ptr = eina_hash_find(ctx->other, key);
+ if (!other_ptr) return EINA_TRUE;
+ ctx->cmp = ctx->subtype->compare(ctx->subtype, self_ptr, other_ptr);
+ return ctx->cmp == 0;
+}
+
+static int
+_eina_value_type_hash_compare(const Eina_Value_Type *type __UNUSED__, const void *a, const void *b)
+{
+ const Eina_Value_Hash *eva_a = a, *eva_b = b;
+ struct _eina_value_type_hash_compare_each_ctx ctx = {
+ eva_a->subtype, eva_b->hash, 0
+ };
+
+ if (eva_a->subtype != eva_b->subtype)
+ {
+ eina_error_set(EINA_ERROR_VALUE_FAILED);
+ return -1;
+ }
+
+ if (!eva_a->subtype->compare)
+ {
+ eina_error_set(EINA_ERROR_VALUE_FAILED);
+ return 0;
+ }
+
+ if ((!eva_a->hash) && (!eva_b->hash))
+ return 0;
+ else if (!eva_a->hash)
+ return -1;
+ else if (!eva_b->hash)
+ return 1;
+
+ eina_hash_foreach(eva_a->hash, _eina_value_type_hash_compare_each, &ctx);
+ if (ctx.cmp == 0)
+ {
+ unsigned int count_a = eina_hash_population(eva_a->hash);
+ unsigned int count_b = eina_hash_population(eva_b->hash);
+ if (count_a < count_b)
+ return -1;
+ else if (count_a > count_b)
+ return 1;
+ return 0;
+ }
+
+ return ctx.cmp;
+}
+
+static Eina_Bool
+_eina_value_type_hash_find_first(const Eina_Hash *hash __UNUSED__, const void *key __UNUSED__, void *ptr, void *user_data)
+{
+ void **ret = user_data;
+ *ret = ptr;
+ return EINA_FALSE;
+}
+
+struct _eina_value_type_hash_convert_to_string_each_ctx
+{
+ const Eina_Value_Type *subtype;
+ Eina_Strbuf *str;
+ Eina_Value tmp;
+ Eina_Bool first;
+};
+
+static Eina_Bool
+_eina_value_type_hash_convert_to_string_each(const Eina_Hash *hash __UNUSED__, const void *_key, void *_ptr, void *user_data)
+{
+ struct _eina_value_type_hash_convert_to_string_each_ctx *ctx = user_data;
+ const char *key = _key;
+ const void *ptr = _ptr;
+ Eina_Bool r = EINA_FALSE;
+
+ if (ctx->first) ctx->first = EINA_FALSE;
+ else eina_strbuf_append_length(ctx->str, ", ", 2);
+
+ eina_strbuf_append(ctx->str, key);
+ eina_strbuf_append_length(ctx->str, ": ", 2);
+
+ if (ctx->subtype->convert_to)
+ {
+ r = ctx->subtype->convert_to(ctx->subtype, EINA_VALUE_TYPE_STRING,
+ ptr, ctx->tmp.value.buf);
+ if (r)
+ {
+ eina_strbuf_append(ctx->str, ctx->tmp.value.ptr);
+ free(ctx->tmp.value.ptr);
+ ctx->tmp.value.ptr = NULL;
+ }
+ }
+
+ if (!r)
+ eina_strbuf_append_char(ctx->str, '?');
+
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_eina_value_type_hash_convert_to(const Eina_Value_Type *type __UNUSED__, const Eina_Value_Type *convert, const void *type_mem, void *convert_mem)
+{
+ const Eina_Value_Hash *tmem = type_mem;
+ Eina_Bool ret = EINA_FALSE;
+
+ if ((convert == EINA_VALUE_TYPE_STRING) ||
+ (convert == EINA_VALUE_TYPE_STRINGSHARE))
+ {
+ Eina_Strbuf *str = eina_strbuf_new();
+ if (!tmem->hash) eina_strbuf_append(str, "{}");
+ else
+ {
+ struct _eina_value_type_hash_convert_to_string_each_ctx ctx;
+ const char *s;
+
+ ctx.subtype = tmem->subtype;
+ ctx.str = str;
+ ctx.first = EINA_TRUE;
+ eina_value_setup(&ctx.tmp, EINA_VALUE_TYPE_STRING);
+
+ eina_strbuf_append_char(str, '{');
+
+ eina_hash_foreach(tmem->hash,
+ _eina_value_type_hash_convert_to_string_each,
+ &ctx);
+
+ eina_strbuf_append_char(str, '}');
+ s = eina_strbuf_string_get(str);
+ ret = eina_value_type_pset(convert, convert_mem, &s);
+ eina_strbuf_free(str);
+ }
+ }
+ else if ((tmem->hash) && (eina_hash_population(tmem->hash) == 1))
+ {
+ const Eina_Value_Type *subtype = tmem->subtype;
+ void *imem = NULL;
+
+ eina_hash_foreach(tmem->hash, _eina_value_type_hash_find_first, &imem);
+ if (!imem) /* shouldn't happen... */
+ ret = EINA_FALSE;
+ else
+ {
+ if (subtype->convert_to)
+ ret = subtype->convert_to(subtype, convert, imem, convert_mem);
+ if ((!ret) && (convert->convert_from))
+ ret = convert->convert_from(convert, subtype, convert_mem, imem);
+ }
+ }
+
+ if (!ret)
+ {
+ eina_error_set(EINA_ERROR_VALUE_FAILED);
+ return EINA_FALSE;
+ }
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_eina_value_type_hash_pset(const Eina_Value_Type *type __UNUSED__, void *mem, const void *ptr)
+{
+ Eina_Value_Hash *tmem = mem;
+ const Eina_Value_Hash *desc = ptr;
+ unsigned int buckets_power;
+
+ if ((!tmem->subtype) && (!desc->subtype))
+ return EINA_TRUE;
+
+ if (desc->buckets_power_size)
+ buckets_power = desc->buckets_power_size;
+ else
+ buckets_power = 5;
+
+ if (tmem->hash) _eina_value_type_hash_flush_elements(tmem);
+
+ if (!_eina_value_type_hash_create(tmem))
+ return EINA_FALSE;
+
+ tmem->subtype = desc->subtype;
+
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_eina_value_type_hash_vset(const Eina_Value_Type *type, void *mem, va_list args)
+{
+ const Eina_Value_Hash desc = va_arg(args, Eina_Value_Hash);
+ _eina_value_type_hash_pset(type, mem, &desc);
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_eina_value_type_hash_pget(const Eina_Value_Type *type __UNUSED__, const void *mem, void *ptr)
+{
+ memcpy(ptr, mem, sizeof(Eina_Value_Hash));
+ return EINA_TRUE;
+}
+
+static const Eina_Value_Type _EINA_VALUE_TYPE_HASH = {
+ EINA_VALUE_TYPE_VERSION,
+ sizeof(Eina_Value_Hash),
+ "Eina_Value_Hash",
+ _eina_value_type_hash_setup,
+ _eina_value_type_hash_flush,
+ _eina_value_type_hash_copy,
+ _eina_value_type_hash_compare,
+ _eina_value_type_hash_convert_to,
+ NULL, /* no convert from */
+ _eina_value_type_hash_vset,
+ _eina_value_type_hash_pset,
+ _eina_value_type_hash_pget
+};
+
/* keep all basic types inlined in an array so we can compare if it's
* a basic type using pointer arithmetic.
*
EINA_VALUE_TYPE_ARRAY = &_EINA_VALUE_TYPE_ARRAY;
EINA_VALUE_TYPE_LIST = &_EINA_VALUE_TYPE_LIST;
+ EINA_VALUE_TYPE_HASH = &_EINA_VALUE_TYPE_HASH;
return EINA_TRUE;
}
EAPI const Eina_Value_Type *EINA_VALUE_TYPE_STRING = NULL;
EAPI const Eina_Value_Type *EINA_VALUE_TYPE_ARRAY = NULL;
EAPI const Eina_Value_Type *EINA_VALUE_TYPE_LIST = NULL;
+EAPI const Eina_Value_Type *EINA_VALUE_TYPE_HASH = NULL;
EAPI Eina_Error EINA_ERROR_VALUE_FAILED = 0;
return value;
}
+EAPI Eina_Value *
+eina_value_hash_new(const Eina_Value_Type *subtype, unsigned int buckets_power_size)
+{
+ Eina_Value *value;
+
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(eina_value_type_check(subtype), EINA_FALSE);
+
+ value = calloc(1, sizeof(Eina_Value));
+ if (!value)
+ return NULL;
+
+ if (!eina_value_hash_setup(value, subtype, buckets_power_size))
+ {
+ free(value);
+ return NULL;
+ }
+
+ return value;
+}
+
EAPI Eina_Bool
eina_value_type_check(const Eina_Value_Type *type)
{
fail_unless(eina_value_list_set(b, 0, 10));
fail_unless(eina_value_compare(a, b) < 0);
+ eina_value_flush(a);
+ eina_value_flush(b);
+
+ fail_unless(eina_value_hash_setup(a, EINA_VALUE_TYPE_CHAR, 0));
+ fail_unless(eina_value_hash_setup(b, EINA_VALUE_TYPE_CHAR, 0));
+ fail_unless(eina_value_compare(a, b) == 0);
+
+ fail_unless(eina_value_hash_set(a, "abc", 1));
+ fail_unless(eina_value_hash_set(a, "xyz", 2));
+ fail_unless(eina_value_hash_set(a, "hello", 3));
+
+ fail_unless(eina_value_hash_set(b, "abc", 1));
+ fail_unless(eina_value_hash_set(b, "xyz", 2));
+ fail_unless(eina_value_hash_set(b, "hello", 3));
+
+ fail_unless(eina_value_compare(a, b) == 0);
+
+ fail_unless(eina_value_hash_set(a, "abc", 0));
+ fail_unless(eina_value_compare(a, b) < 0);
+
+ fail_unless(eina_value_hash_set(a, "abc", 10));
+ fail_unless(eina_value_compare(a, b) > 0);
+
+ fail_unless(eina_value_hash_set(a, "abc", 1));
+
+ fail_unless(eina_value_hash_set(b, "abc", 0));
+ fail_unless(eina_value_compare(a, b) > 0);
+
+ fail_unless(eina_value_hash_set(b, "abc", 10));
+ fail_unless(eina_value_compare(a, b) < 0);
+
+ fail_unless(eina_value_hash_set(b, "abc", 1));
+ fail_unless(eina_value_compare(a, b) == 0);
+
+ /* bigger hashs are greater */
+ fail_unless(eina_value_hash_set(b,"newkey", 0));
+ fail_unless(eina_value_compare(a, b) < 0);
+
+ fail_unless(eina_value_hash_set(a, "newkey", 0));
+ fail_unless(eina_value_hash_set(a, "onemorenewkey", 0));
+ fail_unless(eina_value_compare(a, b) > 0);
+
+ /* bigger hashs are greater, unless an element says otherwise */
+ fail_unless(eina_value_hash_set(b, "abc", 10));
+ fail_unless(eina_value_compare(a, b) < 0);
+
eina_value_free(a);
eina_value_free(b);
eina_shutdown();
}
END_TEST
+START_TEST(eina_value_test_hash)
+{
+ Eina_Value *value, other;
+ char c;
+ char buf[1024];
+ char *str;
+
+ eina_init();
+
+ value = eina_value_hash_new(EINA_VALUE_TYPE_CHAR, 0);
+ fail_unless(value != NULL);
+
+ fail_unless(eina_value_hash_set(value, "first", 'k'));
+ fail_unless(eina_value_hash_set(value, "second", '-'));
+ fail_unless(eina_value_hash_set(value, "third", 's'));
+
+ fail_unless(eina_value_hash_get(value, "first", &c));
+ fail_unless(c == 'k');
+ fail_unless(eina_value_hash_get(value, "second", &c));
+ fail_unless(c == '-');
+ fail_unless(eina_value_hash_get(value, "third", &c));
+ fail_unless(c == 's');
+
+ fail_unless(eina_value_hash_set(value, "first", '!'));
+ fail_unless(eina_value_hash_get(value, "first", &c));
+ fail_unless(c == '!');
+ fail_unless(eina_value_hash_get(value, "second", &c));
+ fail_unless(c == '-');
+ fail_unless(eina_value_hash_get(value, "third", &c));
+ fail_unless(c == 's');
+
+ puts("testing hash to string -- may fail due hash algorithm changes!");
+
+ /* watchout, this is the order I got -- hash algorithm changes may change
+ * the order!
+ */
+ snprintf(buf, sizeof(buf), "{first: %hhd, second: %hhd, third: %hhd}",
+ '!', '-', 's');
+
+ str = eina_value_to_string(value);
+ fail_unless(str != NULL);
+ printf("want: %s\n", buf);
+ printf("got.: %s\n", str);
+ fail_unless(strcmp(str, buf) == 0);
+ free(str);
+
+ eina_value_flush(value);
+ fail_unless(eina_value_hash_setup(value, EINA_VALUE_TYPE_STRINGSHARE, 0));
+
+ fail_unless(eina_value_hash_set(value, "a", "Enlightenment.org"));
+ fail_unless(eina_value_hash_set(value, "b", "X11"));
+ fail_unless(eina_value_hash_set(value, "c", "Pants"));
+ fail_unless(eina_value_hash_set(value, "d", "on!!!"));
+ fail_unless(eina_value_hash_set(value, "e", "k-s"));
+
+ /* watchout, this is the order I got -- hash algorithm changes may change
+ * the order!
+ */
+ strcpy(buf, "{e: k-s, d: on!!!, a: Enlightenment.org, b: X11, c: Pants}");
+
+ str = eina_value_to_string(value);
+ fail_unless(str != NULL);
+ printf("want: %s\n", buf);
+ printf("got.: %s\n", str);
+ fail_unless(strcmp(str, buf) == 0);
+ free(str);
+
+ eina_value_flush(value);
+ fail_unless(eina_value_hash_setup(value, EINA_VALUE_TYPE_CHAR, 0));
+ fail_unless(eina_value_setup(&other, EINA_VALUE_TYPE_CHAR));
+
+ fail_unless(eina_value_set(&other, 100));
+ fail_unless(eina_value_get(&other, &c));
+ fail_unless(c == 100);
+
+ fail_unless(eina_value_hash_set(value, "first", 33));
+ fail_unless(eina_value_convert(value, &other));
+ fail_unless(eina_value_get(&other, &c));
+ fail_unless(c == 33);
+
+ eina_value_free(value);
+ eina_shutdown();
+}
+END_TEST
+
void
eina_test_value(TCase *tc)
{
// TODO: other converters...
tcase_add_test(tc, eina_value_test_array);
tcase_add_test(tc, eina_value_test_list);
+ tcase_add_test(tc, eina_value_test_hash);
}