From 4e74c624d805eedc14d4778dde0eeffe415b90c3 Mon Sep 17 00:00:00 2001 From: Gustavo Sverzut Barbieri Date: Wed, 11 Jan 2012 23:54:35 +0000 Subject: [PATCH] eina_value: add hash. Similar to list and array, but takes string keys instead of position. It can convert to string, I've added tests for it, but hash algorithm changes may break the simple comparison I did... and I don't want to parse the string to be more accurate. SVN revision: 67103 --- legacy/eina/src/include/eina_inline_value.x | 202 ++++++++++ legacy/eina/src/include/eina_value.h | 386 ++++++++++++++++++- legacy/eina/src/lib/eina_value.c | 387 ++++++++++++++++++++ legacy/eina/src/tests/eina_test_value.c | 132 +++++++ 4 files changed, 1099 insertions(+), 8 deletions(-) diff --git a/legacy/eina/src/include/eina_inline_value.x b/legacy/eina/src/include/eina_inline_value.x index 31b330f87b..e059407c27 100644 --- a/legacy/eina/src/include/eina_inline_value.x +++ b/legacy/eina/src/include/eina_inline_value.x @@ -1220,6 +1220,208 @@ eina_value_list_pappend(Eina_Value *value, const void *ptr) } #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) diff --git a/legacy/eina/src/include/eina_value.h b/legacy/eina/src/include/eina_value.h index 365302e856..6a4c217afd 100644 --- a/legacy/eina/src/include/eina_value.h +++ b/legacy/eina/src/include/eina_value.h @@ -23,6 +23,7 @@ #include "eina_fp.h" /* defines int64_t and uint64_t */ #include "eina_inarray.h" #include "eina_list.h" +#include "eina_hash.h" #include /** @@ -222,6 +223,19 @@ EAPI extern const Eina_Value_Type *EINA_VALUE_TYPE_ARRAY; */ 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 @@ -383,6 +397,7 @@ static inline int eina_value_compare(const Eina_Value *a, * @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); @@ -400,6 +415,7 @@ static inline int eina_value_compare(const Eina_Value *a, * * @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() @@ -439,6 +455,7 @@ static inline Eina_Bool eina_value_set(Eina_Value *value, * @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); @@ -459,6 +476,7 @@ static inline Eina_Bool eina_value_set(Eina_Value *value, * * @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() @@ -477,6 +495,7 @@ static inline Eina_Bool eina_value_get(const Eina_Value *value, * * @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() @@ -500,6 +519,7 @@ static inline Eina_Bool eina_value_vset(Eina_Value *value, * * @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() @@ -535,6 +555,7 @@ static inline Eina_Bool eina_value_vget(const Eina_Value *value, * @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. @@ -556,6 +577,7 @@ static inline Eina_Bool eina_value_vget(const Eina_Value *value, * * @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() @@ -596,6 +618,7 @@ static inline Eina_Bool eina_value_pset(Eina_Value *value, * @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); @@ -616,6 +639,7 @@ static inline Eina_Bool eina_value_pset(Eina_Value *value, * * @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() @@ -800,9 +824,11 @@ static inline Eina_Bool eina_value_array_remove(Eina_Value *value, * @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); @@ -856,9 +882,11 @@ static inline Eina_Bool eina_value_array_set(Eina_Value *value, * @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); @@ -900,9 +928,11 @@ static inline Eina_Bool eina_value_array_get(const Eina_Value *value, * @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); @@ -950,9 +980,11 @@ static inline Eina_Bool eina_value_array_insert(Eina_Value *value, * @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); @@ -1086,12 +1118,14 @@ static inline Eina_Bool eina_value_array_vappend(Eina_Value *value, * @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); @@ -1146,9 +1180,11 @@ static inline Eina_Bool eina_value_array_pset(Eina_Value *value, * @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); @@ -1191,12 +1227,14 @@ static inline Eina_Bool eina_value_array_pget(const Eina_Value *value, * @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); @@ -1244,12 +1282,14 @@ static inline Eina_Bool eina_value_array_pinsert(Eina_Value *value, * @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); @@ -1867,6 +1907,336 @@ static inline Eina_Bool eina_value_list_pappend(Eina_Value *value, * @} */ +/** + * @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 * diff --git a/legacy/eina/src/lib/eina_value.c b/legacy/eina/src/lib/eina_value.c index 5751e0636d..22b28c57c7 100644 --- a/legacy/eina/src/lib/eina_value.c +++ b/legacy/eina/src/lib/eina_value.c @@ -2962,6 +2962,371 @@ static const Eina_Value_Type _EINA_VALUE_TYPE_LIST = { _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. * @@ -3221,6 +3586,7 @@ eina_value_init(void) 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; } @@ -3271,6 +3637,7 @@ EAPI const Eina_Value_Type *EINA_VALUE_TYPE_STRINGSHARE = NULL; 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; @@ -3421,6 +3788,26 @@ eina_value_list_new(const Eina_Value_Type *subtype) 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) { diff --git a/legacy/eina/src/tests/eina_test_value.c b/legacy/eina/src/tests/eina_test_value.c index 101890b880..5688365bc4 100644 --- a/legacy/eina/src/tests/eina_test_value.c +++ b/legacy/eina/src/tests/eina_test_value.c @@ -380,6 +380,52 @@ START_TEST(eina_value_test_compare) 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(); @@ -1176,6 +1222,91 @@ START_TEST(eina_value_test_list) } 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) { @@ -1189,4 +1320,5 @@ 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); }