From 16c03cc0143ddaac0ccac2998685d4ab8816f1a6 Mon Sep 17 00:00:00 2001 From: Gustavo Sverzut Barbieri Date: Wed, 11 Jan 2012 21:52:32 +0000 Subject: [PATCH] eina_value: add list type. Similar to array, but less efficient as uses list nodes. If possible values are stored on list->data itself, otherwise they are allocated and the pointer goes as list->data. SVN revision: 67096 --- legacy/eina/src/include/eina_inline_value.x | 386 ++++++++++++ legacy/eina/src/include/eina_value.h | 615 ++++++++++++++++++++ legacy/eina/src/lib/eina_value.c | 351 ++++++++++- legacy/eina/src/tests/eina_test_value.c | 136 +++++ 4 files changed, 1475 insertions(+), 13 deletions(-) diff --git a/legacy/eina/src/include/eina_inline_value.x b/legacy/eina/src/include/eina_inline_value.x index 08393c9308..31b330f87b 100644 --- a/legacy/eina/src/include/eina_inline_value.x +++ b/legacy/eina/src/include/eina_inline_value.x @@ -834,6 +834,392 @@ eina_value_array_pappend(Eina_Value *value, const void *ptr) #undef EINA_VALUE_TYPE_ARRAY_CHECK_RETURN_VAL +#define EINA_VALUE_TYPE_LIST_CHECK_RETURN_VAL(value, retval) \ + EINA_SAFETY_ON_NULL_RETURN_VAL(value, retval); \ + EINA_SAFETY_ON_FALSE_RETURN_VAL(value->type == EINA_VALUE_TYPE_LIST, retval) + +static inline void * +eina_value_list_node_memory_get(const Eina_Value_Type *type, const Eina_List *node) +{ + if (node == NULL) return NULL; + if (type->value_size <= sizeof(void*)) + return (void *)&(node->data); + return node->data; +} + +static inline void * +eina_value_list_node_memory_setup(const Eina_Value_Type *type, Eina_List *node) +{ + if (type->value_size <= sizeof(void*)) + return (void *)&(node->data); + node->data = malloc(type->value_size); + return node->data; +} + +static inline void +eina_value_list_node_memory_flush(const Eina_Value_Type *type, Eina_List *node) +{ + if (type->value_size <= sizeof(void*)) + return; + free(node->data); +} + +static inline Eina_Bool +eina_value_list_setup(Eina_Value *value, const Eina_Value_Type *subtype) +{ + Eina_Value_List desc = { subtype, NULL }; + if (!eina_value_setup(value, EINA_VALUE_TYPE_LIST)) + 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_list_count(const Eina_Value *value) +{ + Eina_Value_List *desc; + EINA_VALUE_TYPE_LIST_CHECK_RETURN_VAL(value, 0); + desc = eina_value_memory_get(value); + if (!desc) + return 0; + return eina_list_count(desc->list); +} + +static inline Eina_Bool +eina_value_list_remove(Eina_Value *value, unsigned int position) +{ + Eina_Value_List *desc; + Eina_List *node; + void *mem; + + EINA_VALUE_TYPE_LIST_CHECK_RETURN_VAL(value, 0); + desc = eina_value_memory_get(value); + if (!desc) + return EINA_FALSE; + + node = eina_list_nth_list(desc->list, position); + mem = eina_value_list_node_memory_get(desc->subtype, node); + if (!mem) + return EINA_FALSE; + + eina_value_type_flush(desc->subtype, mem); + eina_value_list_node_memory_flush(desc->subtype, node); + desc->list = eina_list_remove_list(desc->list, node); + return EINA_TRUE; +} + +static inline Eina_Bool +eina_value_list_vset(Eina_Value *value, unsigned int position, va_list args) +{ + Eina_Value_List *desc; + Eina_List *node; + void *mem; + + EINA_VALUE_TYPE_LIST_CHECK_RETURN_VAL(value, 0); + desc = eina_value_memory_get(value); + if (!desc) + return EINA_FALSE; + + node = eina_list_nth_list(desc->list, position); + mem = eina_value_list_node_memory_get(desc->subtype, node); + if (!mem) + return EINA_FALSE; + + eina_value_type_flush(desc->subtype, mem); + + 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: + return EINA_FALSE; +} + +static inline Eina_Bool +eina_value_list_vget(const Eina_Value *value, unsigned int position, va_list args) +{ + Eina_Value_List *desc; + const Eina_List *node; + const void *mem; + void *ptr; + Eina_Bool ret; + + EINA_VALUE_TYPE_LIST_CHECK_RETURN_VAL(value, 0); + desc = eina_value_memory_get(value); + if (!desc) + return EINA_FALSE; + + node = eina_list_nth_list(desc->list, position); + mem = eina_value_list_node_memory_get(desc->subtype, node); + 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_list_vinsert(Eina_Value *value, unsigned int position, va_list args) +{ + Eina_Value_List *desc; + Eina_List *node; + void *mem; + + EINA_VALUE_TYPE_LIST_CHECK_RETURN_VAL(value, 0); + desc = eina_value_memory_get(value); + if (!desc) + return EINA_FALSE; + + if (!desc->list) + node = desc->list = eina_list_append(NULL, (void*)1L); + else if (position == 0) + node = desc->list = eina_list_prepend(desc->list, (void*)1L); + else + { + Eina_List *rel = eina_list_nth_list(desc->list, position - 1); + desc->list = eina_list_append_relative_list(desc->list, (void*)1L, rel); + node = rel->next; + } + EINA_SAFETY_ON_NULL_RETURN_VAL(node, EINA_FALSE); + EINA_SAFETY_ON_FALSE_RETURN_VAL(node->data == (void*)1L, EINA_FALSE); + + mem = eina_value_list_node_memory_setup(desc->subtype, node); + if (!mem) + { + desc->list = eina_list_remove_list(desc->list, node); + 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_value_list_node_memory_flush(desc->subtype, node); + desc->list = eina_list_remove_list(desc->list, node); + return EINA_FALSE; +} + +static inline Eina_Bool +eina_value_list_vappend(Eina_Value *value, va_list args) +{ + Eina_Value_List *desc; + Eina_List *node; + void *mem; + + EINA_VALUE_TYPE_LIST_CHECK_RETURN_VAL(value, 0); + desc = eina_value_memory_get(value); + if (!desc) + return EINA_FALSE; + + desc->list = eina_list_append(desc->list, (void*)1L); + node = eina_list_last(desc->list); + EINA_SAFETY_ON_NULL_RETURN_VAL(node, EINA_FALSE); + EINA_SAFETY_ON_FALSE_RETURN_VAL(node->data == (void*)1L, EINA_FALSE); + + mem = eina_value_list_node_memory_setup(desc->subtype, node); + if (!mem) + { + desc->list = eina_list_remove_list(desc->list, node); + 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_value_list_node_memory_flush(desc->subtype, node); + desc->list = eina_list_remove_list(desc->list, node); + return EINA_FALSE; +} + +static inline Eina_Bool +eina_value_list_set(Eina_Value *value, unsigned int position, ...) +{ + va_list args; + Eina_Bool ret; + va_start(args, position); + ret = eina_value_list_vset(value, position, args); + va_end(args); + return ret; +} + +static inline Eina_Bool +eina_value_list_get(const Eina_Value *value, unsigned int position, ...) +{ + va_list args; + Eina_Bool ret; + va_start(args, position); + ret = eina_value_list_vget(value, position, args); + va_end(args); + return ret; +} + +static inline Eina_Bool +eina_value_list_insert(Eina_Value *value, unsigned int position, ...) +{ + va_list args; + Eina_Bool ret; + va_start(args, position); + ret = eina_value_list_vinsert(value, position, args); + va_end(args); + return ret; +} + +static inline Eina_Bool eina_value_list_append(Eina_Value *value, ...) +{ + va_list args; + Eina_Bool ret; + va_start(args, value); + ret = eina_value_list_vappend(value, args); + va_end(args); + return ret; +} + +static inline Eina_Bool +eina_value_list_pset(Eina_Value *value, unsigned int position, const void *ptr) +{ + Eina_Value_List *desc; + Eina_List *node; + void *mem; + + EINA_VALUE_TYPE_LIST_CHECK_RETURN_VAL(value, 0); + desc = eina_value_memory_get(value); + if (!desc) + return EINA_FALSE; + + node = eina_list_nth_list(desc->list, position); + mem = eina_value_list_node_memory_get(desc->subtype, node); + if (!mem) + return EINA_FALSE; + + eina_value_type_flush(desc->subtype, mem); + + 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: + return EINA_FALSE; +} + +static inline Eina_Bool +eina_value_list_pget(const Eina_Value *value, unsigned int position, void *ptr) +{ + Eina_Value_List *desc; + const Eina_List *node; + const void *mem; + Eina_Bool ret; + + EINA_VALUE_TYPE_LIST_CHECK_RETURN_VAL(value, 0); + desc = eina_value_memory_get(value); + if (!desc) + return EINA_FALSE; + + node = eina_list_nth_list(desc->list, position); + mem = eina_value_list_node_memory_get(desc->subtype, node); + if (!mem) + return EINA_FALSE; + + ret = eina_value_type_pget(desc->subtype, mem, ptr); + return ret; +} + +static inline Eina_Bool +eina_value_list_pinsert(Eina_Value *value, unsigned int position, const void *ptr) +{ + Eina_Value_List *desc; + Eina_List *node; + void *mem; + + EINA_VALUE_TYPE_LIST_CHECK_RETURN_VAL(value, 0); + desc = eina_value_memory_get(value); + if (!desc) + return EINA_FALSE; + + if (!desc->list) + node = desc->list = eina_list_append(NULL, (void*)1L); + else if (position == 0) + node = desc->list = eina_list_prepend(desc->list, (void*)1L); + else + { + Eina_List *rel = eina_list_nth_list(desc->list, position - 1); + desc->list = eina_list_append_relative_list(desc->list, (void*)1L, rel); + node = rel->next; + } + EINA_SAFETY_ON_NULL_RETURN_VAL(node, EINA_FALSE); + EINA_SAFETY_ON_FALSE_RETURN_VAL(node->data == (void*)1L, EINA_FALSE); + + mem = eina_value_list_node_memory_setup(desc->subtype, node); + if (!mem) + { + desc->list = eina_list_remove_list(desc->list, node); + 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_value_list_node_memory_flush(desc->subtype, node); + desc->list = eina_list_remove_list(desc->list, node); + return EINA_FALSE; +} + +static inline Eina_Bool +eina_value_list_pappend(Eina_Value *value, const void *ptr) +{ + Eina_Value_List *desc; + Eina_List *node; + void *mem; + + EINA_VALUE_TYPE_LIST_CHECK_RETURN_VAL(value, 0); + desc = eina_value_memory_get(value); + if (!desc) + return EINA_FALSE; + + desc->list = eina_list_append(desc->list, (void*)1L); + node = eina_list_last(desc->list); + EINA_SAFETY_ON_NULL_RETURN_VAL(node, EINA_FALSE); + EINA_SAFETY_ON_FALSE_RETURN_VAL(node->data == (void*)1L, EINA_FALSE); + + mem = eina_value_list_node_memory_setup(desc->subtype, node); + if (!mem) + { + desc->list = eina_list_remove_list(desc->list, node); + 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_value_list_node_memory_flush(desc->subtype, node); + desc->list = eina_list_remove_list(desc->list, node); + return EINA_FALSE; +} +#undef EINA_VALUE_TYPE_LIST_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 2b322b009c..365302e856 100644 --- a/legacy/eina/src/include/eina_value.h +++ b/legacy/eina/src/include/eina_value.h @@ -22,6 +22,7 @@ #include "eina_types.h" #include "eina_fp.h" /* defines int64_t and uint64_t */ #include "eina_inarray.h" +#include "eina_list.h" #include /** @@ -208,6 +209,19 @@ EAPI extern const Eina_Value_Type *EINA_VALUE_TYPE_STRING; */ EAPI extern const Eina_Value_Type *EINA_VALUE_TYPE_ARRAY; +/** + * @var EINA_VALUE_TYPE_LIST + * + * manages list type. The value get/set are the type of elements in + * the list, use the alternaties: + * @li eina_value_list_get() and eina_value_list_set() + * @li eina_value_list_vget() and eina_value_list_vset() + * @li eina_value_list_pget() and eina_value_list_pset() + * + * @since 1.2 + */ +EAPI extern const Eina_Value_Type *EINA_VALUE_TYPE_LIST; + /** * @var EINA_ERROR_VALUE_FAILED @@ -368,6 +382,7 @@ static inline int eina_value_compare(const Eina_Value *a, * @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 * * @code * Eina_Value *value = eina_value_new(EINA_VALUE_TYPE_INT); @@ -384,6 +399,7 @@ static inline int eina_value_compare(const Eina_Value *a, * @endcode * * @note for array member see eina_value_array_set() + * @note for list member see eina_value_list_set() * * @see eina_value_get() * @see eina_value_vset() @@ -422,6 +438,7 @@ static inline Eina_Bool eina_value_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* * * @code * Eina_Value *value = eina_value_new(EINA_VALUE_TYPE_INT); @@ -441,6 +458,7 @@ static inline Eina_Bool eina_value_set(Eina_Value *value, * @endcode * * @note for array member see eina_value_array_get() + * @note for list member see eina_value_list_get() * * @see eina_value_set() * @see eina_value_vset() @@ -458,6 +476,7 @@ static inline Eina_Bool eina_value_get(const Eina_Value *value, * @return #EINA_TRUE on success, #EINA_FALSE otherwise. * * @note for array member see eina_value_array_vset() + * @note for list member see eina_value_list_vset() * * @see eina_value_vget() * @see eina_value_set() @@ -480,6 +499,7 @@ static inline Eina_Bool eina_value_vset(Eina_Value *value, * thus the contents should @b not be free'd. * * @note for array member see eina_value_array_vget() + * @note for list member see eina_value_list_vget() * * @see eina_value_vset() * @see eina_value_get() @@ -514,6 +534,7 @@ static inline Eina_Bool eina_value_vget(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* * * @note the pointer contents are written using the size defined by * type. It can be larger than void* or uint64_t. @@ -534,6 +555,7 @@ static inline Eina_Bool eina_value_vget(const Eina_Value *value, * @endcode * * @note for array member see eina_value_array_pset() + * @note for list member see eina_value_list_pset() * * @see eina_value_pget() * @see eina_value_set() @@ -573,6 +595,7 @@ static inline Eina_Bool eina_value_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* * * @code * Eina_Value *value = eina_value_new(EINA_VALUE_TYPE_INT); @@ -592,6 +615,7 @@ static inline Eina_Bool eina_value_pset(Eina_Value *value, * @endcode * * @note for array member see eina_value_array_get() + * @note for list member see eina_value_list_get() * * @see eina_value_set() * @see eina_value_vset() @@ -1252,6 +1276,597 @@ static inline Eina_Bool eina_value_array_pappend(Eina_Value *value, * @} */ + +/** + * @defgroup Eina_Value_List_Group Generic Value List management + * + * @{ + */ + + +/** + * @typedef Eina_Value_List + * Value type for #EINA_VALUE_TYPE_LIST + * + * @since 1.2 + */ +typedef struct _Eina_Value_List Eina_Value_List; + +/** + * @struct _Eina_Value_List + * Used to store the list and its subtype. + */ +struct _Eina_Value_List +{ + const Eina_Value_Type *subtype; /**< how to allocate and access items */ + Eina_List *list; /**< the list that holds data, members are of subtype->value_size bytes. */ +}; + +/** + * @brief Create generic value storage of type list. + * @param subtype how to manage this list members. + * @return The new value or @c NULL on failure. + * + * Create a new generic value storage of type list. 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_list_setup() doing malloc + * for you. + * + * @see eina_value_free() + * @see eina_value_list_setup() + * + * @since 1.2 + */ +EAPI Eina_Value *eina_value_list_new(const Eina_Value_Type *subtype) EINA_ARG_NONNULL(1); + +/** + * @brief Setup generic value storage of type list. + * @param value value object + * @param subtype how to manage this list members. + * @return #EINA_TRUE on success, #EINA_FALSE otherwise. + * + * Setups new generic value storage of type list with the given + * @a subtype. + * + * This is the same as calling eina_value_set() with + * #EINA_VALUE_TYPE_LIST followed by eina_value_pset() with the + * #Eina_Value_List 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_list_setup(Eina_Value *value, + const Eina_Value_Type *subtype) EINA_ARG_NONNULL(1, 2); + +/** + * @brief Query number of elements in value of list type. + * @param value value object. + * @return number of child elements. + * @since 1.2 + */ +static inline unsigned int eina_value_list_count(const Eina_Value *value); + +/** + * @brief Remove element at given position in value of list type. + * @param value value object. + * @param position index of the member + * @return #EINA_TRUE on success, #EINA_FALSE otherwise. + * @since 1.2 + */ +static inline Eina_Bool eina_value_list_remove(Eina_Value *value, + unsigned int position) EINA_ARG_NONNULL(1); + +/** + * @brief Set the generic value in an list member. + * @param value source value object + * @param position index of the member + * @return #EINA_TRUE on success, #EINA_FALSE otherwise. + * + * The variable argument is dependent on chosen subtype. The list 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_LIST: Eina_Value_List + * + * @code + * Eina_Value *value = eina_value_list_new(EINA_VALUE_TYPE_INT); + * int x; + * + * eina_value_list_append(value, 1234); + * eina_value_list_set(value, 0, 5678); + * eina_value_list_get(value, 0, &x); + * eina_value_free(value); + * @endcode + * + * @see eina_value_list_get() + * @see eina_value_list_vset() + * @see eina_value_list_pset() + * @see eina_value_list_insert() + * @see eina_value_list_vinsert() + * @see eina_value_list_pinsert() + * @see eina_value_list_append() + * @see eina_value_list_vappend() + * @see eina_value_list_pappend() + * + * @since 1.2 + */ +static inline Eina_Bool eina_value_list_set(Eina_Value *value, + unsigned int position, + ...) EINA_ARG_NONNULL(1); + +/** + * @brief Get the generic value from an list member. + * @param value source value object + * @param position index of 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 list 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_LIST: Eina_Value_List* + * + * @code + * Eina_Value *value = eina_value_list_new(EINA_VALUE_TYPE_INT); + * int x; + * + * eina_value_list_append(value, 1234); + * eina_value_list_get(value, 0, &x); + * eina_value_free(value); + * @endcode + * + * @see eina_value_list_set() + * @see eina_value_list_vset() + * @see eina_value_list_pset() + * + * @since 1.2 + */ +static inline Eina_Bool eina_value_list_get(const Eina_Value *value, + unsigned int position, + ...) EINA_ARG_NONNULL(1); + +/** + * @brief Insert the generic value in an list member position. + * @param value source value object + * @param position index of the member + * @return #EINA_TRUE on success, #EINA_FALSE otherwise. + * + * The variable argument is dependent on chosen subtype. The list 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_LIST: Eina_Value_List + * + * @code + * Eina_Value *value = eina_value_list_new(EINA_VALUE_TYPE_INT); + * int x; + * + * eina_value_list_insert(value, 0, 1234); + * eina_value_list_get(value, 0, &x); + * eina_value_free(value); + * @endcode + * + * @see eina_value_list_set() + * @see eina_value_list_get() + * @see eina_value_list_vset() + * @see eina_value_list_pset() + * @see eina_value_list_vinsert() + * @see eina_value_list_pinsert() + * @see eina_value_list_append() + * @see eina_value_list_vappend() + * @see eina_value_list_pappend() + * + * @since 1.2 + */ +static inline Eina_Bool eina_value_list_insert(Eina_Value *value, + unsigned int position, + ...) EINA_ARG_NONNULL(1); + + +/** + * @brief Append the generic value in an list. + * @param value source value object + * @return #EINA_TRUE on success, #EINA_FALSE otherwise. + * + * The variable argument is dependent on chosen subtype. The list 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_LIST: Eina_Value_List + * + * @code + * Eina_Value *value = eina_value_list_new(EINA_VALUE_TYPE_INT); + * int x; + * + * eina_value_list_append(value, 1234); + * eina_value_list_get(value, 0, &x); + * eina_value_free(value); + * @endcode + * + * @see eina_value_list_set() + * @see eina_value_list_get() + * @see eina_value_list_vset() + * @see eina_value_list_pset() + * @see eina_value_list_vinsert() + * @see eina_value_list_pinsert() + * @see eina_value_list_append() + * @see eina_value_list_vappend() + * @see eina_value_list_pappend() + * + * @since 1.2 + */ +static inline Eina_Bool eina_value_list_append(Eina_Value *value, + ...) EINA_ARG_NONNULL(1); + +/** + * @brief Set the generic value in an list member. + * @param value source value object + * @param position index of the member + * @param args variable argument + * @return #EINA_TRUE on success, #EINA_FALSE otherwise. + * @see eina_value_list_set() + * @see eina_value_list_get() + * @see eina_value_list_pset() + * @see eina_value_list_insert() + * @see eina_value_list_vinsert() + * @see eina_value_list_pinsert() + * @see eina_value_list_append() + * @see eina_value_list_vappend() + * @see eina_value_list_pappend() + * + * @since 1.2 + */ +static inline Eina_Bool eina_value_list_vset(Eina_Value *value, + unsigned int position, + va_list args) EINA_ARG_NONNULL(1); + +/** + * @brief Get the generic value from an list member. + * @param value source value object + * @param position index of 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_list_vset() + * @see eina_value_list_get() + * @see eina_value_list_pget() + * + * @since 1.2 + */ +static inline Eina_Bool eina_value_list_vget(const Eina_Value *value, + unsigned int position, + va_list args) EINA_ARG_NONNULL(1); +/** + * @brief Insert the generic value in an list member position. + * @param value source value object + * @param position index of the member + * @param args variable argument + * @return #EINA_TRUE on success, #EINA_FALSE otherwise. + * @see eina_value_list_set() + * @see eina_value_list_get() + * @see eina_value_list_vset() + * @see eina_value_list_pset() + * @see eina_value_list_insert() + * @see eina_value_list_pinsert() + * @see eina_value_list_append() + * @see eina_value_list_vappend() + * @see eina_value_list_pappend() + * + * @since 1.2 + */ +static inline Eina_Bool eina_value_list_vinsert(Eina_Value *value, + unsigned int position, + va_list args) EINA_ARG_NONNULL(1); + +/** + * @brief Append the generic value in an list. + * @param value source value object + * @param args variable argument + * @return #EINA_TRUE on success, #EINA_FALSE otherwise. + * @see eina_value_list_set() + * @see eina_value_list_get() + * @see eina_value_list_vget() + * @see eina_value_list_pset() + * @see eina_value_list_insert() + * @see eina_value_list_vinsert() + * @see eina_value_list_pinsert() + * @see eina_value_list_append() + * @see eina_value_list_pappend() + * + * @since 1.2 + */ +static inline Eina_Bool eina_value_list_vappend(Eina_Value *value, + va_list args) EINA_ARG_NONNULL(1); + + +/** + * @brief Set the generic value in an list member from pointer. + * @param value source value object + * @param position index of 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 list 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_LIST: Eina_Value_List* + * + * @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_list_new(EINA_VALUE_TYPE_INT); + * int x = 1234; + * + * eina_value_list_append(value, 1234); + * eina_value_list_pset(value, 0, &x); + * eina_value_list_pget(value, 0, &x); + * eina_value_free(value); + * @endcode + * + * @see eina_value_list_set() + * @see eina_value_list_get() + * @see eina_value_list_vset() + * @see eina_value_list_insert() + * @see eina_value_list_vinsert() + * @see eina_value_list_pinsert() + * @see eina_value_list_append() + * @see eina_value_list_vappend() + * @see eina_value_list_pappend() + * + * @since 1.2 + */ +static inline Eina_Bool eina_value_list_pset(Eina_Value *value, + unsigned int position, + const void *ptr) EINA_ARG_NONNULL(1, 3); + +/** + * @brief Get the generic value to pointer from an list member. + * @param value source value object + * @param position index of 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 list 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_LIST: Eina_Value_List* + * + * @code + * Eina_Value *value = eina_value_list_new(EINA_VALUE_TYPE_INT); + * int x; + * + * eina_value_list_append(value, 1234); + * eina_value_list_pget(value, 0, &x); + * eina_value_free(value); + * @endcode + * + * @see eina_value_list_set() + * @see eina_value_list_vset() + * @see eina_value_list_pset() + * + * @since 1.2 + */ +static inline Eina_Bool eina_value_list_pget(const Eina_Value *value, + unsigned int position, + void *ptr) EINA_ARG_NONNULL(1, 3); + +/** + * @brief Insert the generic value in an list member position from pointer. + * @param value source value object + * @param position index of 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 list 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_LIST: Eina_Value_List* + * + * @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_list_new(EINA_VALUE_TYPE_INT); + * int x = 1234; + * + * eina_value_list_pinsert(value, 0, &x); + * eina_value_list_pget(value, 0, &x); + * eina_value_free(value); + * @endcode + * + * @see eina_value_list_set() + * @see eina_value_list_get() + * @see eina_value_list_vset() + * @see eina_value_list_insert() + * @see eina_value_list_vinsert() + * @see eina_value_list_pinsert() + * @see eina_value_list_append() + * @see eina_value_list_vappend() + * @see eina_value_list_pappend() + * + * @since 1.2 + */ +static inline Eina_Bool eina_value_list_pinsert(Eina_Value *value, + unsigned int position, + const void *ptr) EINA_ARG_NONNULL(1); + +/** + * @brief Append the generic value in an list from pointer. + * @param value source value object + * @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 list 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_LIST: Eina_Value_List* + * + * @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_list_new(EINA_VALUE_TYPE_INT); + * int x = 1234; + * + * eina_value_list_pappend(value, &x); + * eina_value_list_pget(value, 0, &x); + * eina_value_free(value); + * @endcode + * + * @see eina_value_list_set() + * @see eina_value_list_get() + * @see eina_value_list_vset() + * @see eina_value_list_insert() + * @see eina_value_list_vinsert() + * @see eina_value_list_pinsert() + * @see eina_value_list_append() + * @see eina_value_list_vappend() + * @see eina_value_list_pappend() + * + * @since 1.2 + */ +static inline Eina_Bool eina_value_list_pappend(Eina_Value *value, + const void *ptr) EINA_ARG_NONNULL(1); + +/** + * @} + */ + /** * @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 17eca0cae2..e3f51e9164 100644 --- a/legacy/eina/src/lib/eina_value.c +++ b/legacy/eina/src/lib/eina_value.c @@ -2397,7 +2397,10 @@ _eina_value_type_array_copy(const Eina_Value_Type *type __UNUSED__, const void * } if (!subtype->copy) - return EINA_FALSE; + { + eina_error_set(EINA_ERROR_VALUE_FAILED); + return EINA_FALSE; + } d->array = eina_inarray_new(subtype->value_size, s->step); if (!d->array) @@ -2494,8 +2497,18 @@ _eina_value_type_array_convert_to(const Eina_Value_Type *type __UNUSED__, const const Eina_Value_Array *tmem = type_mem; Eina_Bool ret = EINA_FALSE; - if ((convert == EINA_VALUE_TYPE_STRING) || - (convert == EINA_VALUE_TYPE_STRINGSHARE)) + if ((tmem->array) && (tmem->array->len == 1)) + { + const Eina_Value_Type *subtype = tmem->subtype; + void *imem = tmem->array->members; + + 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); + } + else if ((convert == EINA_VALUE_TYPE_STRING) || + (convert == EINA_VALUE_TYPE_STRINGSHARE)) { Eina_Strbuf *str = eina_strbuf_new(); if (!tmem->array) eina_strbuf_append(str, "[]"); @@ -2549,16 +2562,6 @@ _eina_value_type_array_convert_to(const Eina_Value_Type *type __UNUSED__, const eina_strbuf_free(str); } } - else if ((tmem->array) && (tmem->array->len == 1)) - { - const Eina_Value_Type *subtype = tmem->subtype; - void *imem = tmem->array->members; - - 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) { @@ -2659,6 +2662,306 @@ static const Eina_Value_Type _EINA_VALUE_TYPE_ARRAY = { _eina_value_type_array_pget }; +static Eina_Bool +_eina_value_type_list_setup(const Eina_Value_Type *type __UNUSED__, void *mem) +{ + memset(mem, 0, sizeof(Eina_Value_List)); + return EINA_TRUE; +} + +static Eina_Bool +_eina_value_type_list_flush_elements(Eina_Value_List *tmem) +{ + const Eina_Value_Type *subtype = tmem->subtype; + Eina_Bool ret = EINA_TRUE; + + if (!tmem->list) return EINA_TRUE; + + while (tmem->list) + { + void *mem = eina_value_list_node_memory_get(tmem->subtype, tmem->list); + ret &= eina_value_type_flush(subtype, mem); + eina_value_list_node_memory_flush(tmem->subtype, tmem->list); + tmem->list = eina_list_remove_list(tmem->list, tmem->list); + } + + return ret; +} + +static Eina_Bool +_eina_value_type_list_flush(const Eina_Value_Type *type __UNUSED__, void *mem) +{ + Eina_Value_List *tmem = mem; + Eina_Bool ret =_eina_value_type_list_flush_elements(tmem); + + if (tmem->list) eina_list_free(tmem->list); + tmem->list = NULL; + tmem->subtype = NULL; + return ret; +} + +static Eina_Bool +_eina_value_type_list_copy(const Eina_Value_Type *type __UNUSED__, const void *src, void *dst) +{ + const Eina_Value_Type *subtype; + const Eina_Value_List *s = src; + Eina_Value_List *d = dst; + const Eina_List *snode; + + d->subtype = subtype = s->subtype; + if ((!s->list) || (!s->subtype)) + { + d->list = NULL; + return EINA_TRUE; + } + + if (!subtype->copy) + { + eina_error_set(EINA_ERROR_VALUE_FAILED); + return EINA_FALSE; + } + + d->list = NULL; + for (snode = s->list; snode != NULL; snode = snode->next) + { + const void *ptr = eina_value_list_node_memory_get(subtype, snode); + Eina_List *dnode; + void *imem; + + d->list = eina_list_append(d->list, (void*)1L); + dnode = eina_list_last(d->list); + EINA_SAFETY_ON_NULL_GOTO(dnode, error); + EINA_SAFETY_ON_FALSE_GOTO(dnode->data == (void*)1L, error); + + imem = eina_value_list_node_memory_setup(subtype, dnode); + if (!subtype->copy(subtype, ptr, imem)) + { + eina_value_list_node_memory_flush(subtype, dnode); + d->list = eina_list_remove_list(d->list, dnode); + goto error; + } + } + return EINA_TRUE; + + error: + _eina_value_type_list_flush_elements(d); + return EINA_FALSE; +} + +static int +_eina_value_type_list_compare(const Eina_Value_Type *type __UNUSED__, const void *a, const void *b) +{ + const Eina_Value_Type *subtype; + const Eina_Value_List *eva_a = a, *eva_b = b; + const Eina_List *anode, *bnode; + int cmp = 0; + + if (eva_a->subtype != eva_b->subtype) + { + eina_error_set(EINA_ERROR_VALUE_FAILED); + return -1; + } + + subtype = eva_a->subtype; + if (!subtype->compare) + { + eina_error_set(EINA_ERROR_VALUE_FAILED); + return 0; + } + + if ((!eva_a->list) && (!eva_b->list)) + return 0; + else if (!eva_a->list) + return -1; + else if (!eva_b->list) + return 1; + + for (anode = eva_a->list, bnode = eva_b->list; + (cmp == 0) && (anode) && (bnode); + anode = anode->next, bnode = bnode->next) + { + const void *amem = eina_value_list_node_memory_get(subtype, anode); + const void *bmem = eina_value_list_node_memory_get(subtype, bnode); + cmp = subtype->compare(subtype, amem, bmem); + } + + if (cmp == 0) + { + if ((!anode) && (bnode)) + return -1; + else if ((anode) && (!bnode)) + return 1; + return 0; + } + + return cmp; +} + +static Eina_Bool +_eina_value_type_list_convert_to(const Eina_Value_Type *type __UNUSED__, const Eina_Value_Type *convert, const void *type_mem, void *convert_mem) +{ + const Eina_Value_List *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->list) eina_strbuf_append(str, "[]"); + else + { + const Eina_Value_Type *subtype = tmem->subtype; + const Eina_List *node; + Eina_Value tmp; + const char *s; + Eina_Bool first = EINA_TRUE; + + eina_value_setup(&tmp, EINA_VALUE_TYPE_STRING); + + eina_strbuf_append_char(str, '['); + + for (node = tmem->list; node != NULL; node = node->next) + { + Eina_Bool r = EINA_FALSE; + + if (subtype->convert_to) + { + const void *ptr; + ptr = eina_value_list_node_memory_get(subtype, node); + r = subtype->convert_to(subtype, EINA_VALUE_TYPE_STRING, + ptr, tmp.value.buf); + if (r) + { + if (first) first = EINA_FALSE; + else eina_strbuf_append_length(str, ", ", 2); + eina_strbuf_append(str, tmp.value.ptr); + free(tmp.value.ptr); + tmp.value.ptr = NULL; + } + } + + if (!r) + { + if (first) + { + first = EINA_FALSE; + eina_strbuf_append_char(str, '?'); + } + else + eina_strbuf_append_length(str, ", ?", 3); + } + } + + 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->list) && (tmem->list->next == NULL)) + { + const Eina_Value_Type *subtype = tmem->subtype; + void *imem = eina_value_list_node_memory_get(subtype, tmem->list); + + 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_list_convert_from(const Eina_Value_Type *type, const Eina_Value_Type *convert, void *type_mem, const void *convert_mem) +{ + Eina_Value_List *tmem = type_mem; + Eina_Value_List desc = {convert, NULL}; + Eina_List *node; + char *buf; + void *imem; + + if (!eina_value_type_pset(type, tmem, &desc)) + return EINA_FALSE; + + buf = alloca(convert->value_size); + if (!eina_value_type_pget(convert, convert_mem, &buf)) + return EINA_FALSE; + + tmem->list = eina_list_append(tmem->list, (void*)1L); + node = eina_list_last(tmem->list); + EINA_SAFETY_ON_NULL_RETURN_VAL(node, EINA_FALSE); + EINA_SAFETY_ON_FALSE_RETURN_VAL(node->data == (void*)1L, EINA_FALSE); + + imem = eina_value_list_node_memory_setup(tmem->subtype, node); + if (!imem) + { + tmem->list = eina_list_remove_list(tmem->list, node); + return EINA_FALSE; + } + + if (!eina_value_type_setup(tmem->subtype, imem)) goto error_setup; + if (!eina_value_type_pset(tmem->subtype, imem, &buf)) goto error_set; + return EINA_TRUE; + + error_set: + eina_value_type_flush(tmem->subtype, imem); + error_setup: + eina_value_list_node_memory_flush(tmem->subtype, node); + tmem->list = eina_list_remove_list(tmem->list, node); + return EINA_FALSE; +} + +static Eina_Bool +_eina_value_type_list_pset(const Eina_Value_Type *type __UNUSED__, void *mem, const void *ptr) +{ + Eina_Value_List *tmem = mem; + const Eina_Value_List *desc = ptr; + + if ((!tmem->subtype) && (!desc->subtype)) + return EINA_TRUE; + + _eina_value_type_list_flush_elements(tmem); + tmem->subtype = desc->subtype; + + return EINA_TRUE; +} + +static Eina_Bool +_eina_value_type_list_vset(const Eina_Value_Type *type, void *mem, va_list args) +{ + const Eina_Value_List desc = va_arg(args, Eina_Value_List); + _eina_value_type_list_pset(type, mem, &desc); + return EINA_TRUE; +} + +static Eina_Bool +_eina_value_type_list_pget(const Eina_Value_Type *type __UNUSED__, const void *mem, void *ptr) +{ + memcpy(ptr, mem, sizeof(Eina_Value_List)); + return EINA_TRUE; +} + +static const Eina_Value_Type _EINA_VALUE_TYPE_LIST = { + EINA_VALUE_TYPE_VERSION, + sizeof(Eina_Value_List), + "Eina_Value_List", + _eina_value_type_list_setup, + _eina_value_type_list_flush, + _eina_value_type_list_copy, + _eina_value_type_list_compare, + _eina_value_type_list_convert_to, + _eina_value_type_list_convert_from, + _eina_value_type_list_vset, + _eina_value_type_list_pset, + _eina_value_type_list_pget +}; + /* keep all basic types inlined in an array so we can compare if it's * a basic type using pointer arithmetic. * @@ -2917,6 +3220,7 @@ eina_value_init(void) EINA_VALUE_TYPE_ARRAY = &_EINA_VALUE_TYPE_ARRAY; + EINA_VALUE_TYPE_LIST = &_EINA_VALUE_TYPE_LIST; return EINA_TRUE; } @@ -2966,6 +3270,7 @@ EAPI const Eina_Value_Type *EINA_VALUE_TYPE_DOUBLE = NULL; 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 Eina_Error EINA_ERROR_VALUE_FAILED = 0; @@ -3096,6 +3401,26 @@ eina_value_array_new(const Eina_Value_Type *subtype, unsigned int step) return value; } +EAPI Eina_Value * +eina_value_list_new(const Eina_Value_Type *subtype) +{ + 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_list_setup(value, subtype)) + { + 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 458f874ed0..cfa7c712b6 100644 --- a/legacy/eina/src/tests/eina_test_value.c +++ b/legacy/eina/src/tests/eina_test_value.c @@ -334,6 +334,52 @@ START_TEST(eina_value_test_compare) fail_unless(eina_value_array_set(b, 0, 10)); fail_unless(eina_value_compare(a, b) < 0); + eina_value_flush(a); + eina_value_flush(b); + + fail_unless(eina_value_list_setup(a, EINA_VALUE_TYPE_CHAR)); + fail_unless(eina_value_list_setup(b, EINA_VALUE_TYPE_CHAR)); + fail_unless(eina_value_compare(a, b) == 0); + + fail_unless(eina_value_list_append(a, 1)); + fail_unless(eina_value_list_append(a, 2)); + fail_unless(eina_value_list_append(a, 3)); + + fail_unless(eina_value_list_append(b, 1)); + fail_unless(eina_value_list_append(b, 2)); + fail_unless(eina_value_list_append(b, 3)); + + fail_unless(eina_value_compare(a, b) == 0); + + fail_unless(eina_value_list_set(a, 0, 0)); + fail_unless(eina_value_compare(a, b) < 0); + + fail_unless(eina_value_list_set(a, 0, 10)); + fail_unless(eina_value_compare(a, b) > 0); + + fail_unless(eina_value_list_set(a, 0, 1)); + + fail_unless(eina_value_list_set(b, 0, 0)); + fail_unless(eina_value_compare(a, b) > 0); + + fail_unless(eina_value_list_set(b, 0, 10)); + fail_unless(eina_value_compare(a, b) < 0); + + fail_unless(eina_value_list_set(b, 0, 1)); + fail_unless(eina_value_compare(a, b) == 0); + + /* bigger lists are greater */ + fail_unless(eina_value_list_append(b, 0)); + fail_unless(eina_value_compare(a, b) < 0); + + fail_unless(eina_value_list_append(a, 0)); + fail_unless(eina_value_list_append(a, 0)); + fail_unless(eina_value_compare(a, b) > 0); + + /* bigger lists are greater, unless an element says otherwise */ + fail_unless(eina_value_list_set(b, 0, 10)); + fail_unless(eina_value_compare(a, b) < 0); + eina_value_free(a); eina_value_free(b); eina_shutdown(); @@ -1022,6 +1068,95 @@ START_TEST(eina_value_test_array) } END_TEST +START_TEST(eina_value_test_list) +{ + Eina_Value *value, other; + char c; + char buf[1024]; + char *str; + + eina_init(); + + value = eina_value_list_new(EINA_VALUE_TYPE_CHAR); + fail_unless(value != NULL); + + fail_unless(eina_value_list_append(value, 'k')); + fail_unless(eina_value_list_append(value, '-')); + fail_unless(eina_value_list_append(value, 's')); + + fail_unless(eina_value_list_get(value, 0, &c)); + fail_unless(c == 'k'); + fail_unless(eina_value_list_get(value, 1, &c)); + fail_unless(c == '-'); + fail_unless(eina_value_list_get(value, 2, &c)); + fail_unless(c == 's'); + + fail_unless(eina_value_list_insert(value, 0, '!')); + fail_unless(eina_value_list_get(value, 0, &c)); + fail_unless(c == '!'); + fail_unless(eina_value_list_get(value, 1, &c)); + fail_unless(c == 'k'); + fail_unless(eina_value_list_get(value, 2, &c)); + fail_unless(c == '-'); + fail_unless(eina_value_list_get(value, 3, &c)); + fail_unless(c == 's'); + + fail_unless(eina_value_list_set(value, 0, '*')); + fail_unless(eina_value_list_get(value, 0, &c)); + fail_unless(c == '*'); + fail_unless(eina_value_list_get(value, 1, &c)); + fail_unless(c == 'k'); + fail_unless(eina_value_list_get(value, 2, &c)); + fail_unless(c == '-'); + fail_unless(eina_value_list_get(value, 3, &c)); + fail_unless(c == 's'); + + snprintf(buf, sizeof(buf), "[%hhd, %hhd, %hhd, %hhd]", + '*', 'k', '-', 's'); + + str = eina_value_to_string(value); + fail_unless(str != NULL); + fail_unless(strcmp(str, buf) == 0); + free(str); + + eina_value_flush(value); + fail_unless(eina_value_list_setup(value, EINA_VALUE_TYPE_STRINGSHARE)); + + fail_unless(eina_value_list_append(value, "Enlightenment.org")); + fail_unless(eina_value_list_append(value, "X11")); + fail_unless(eina_value_list_append(value, "Pants")); + fail_unless(eina_value_list_append(value, "on!!!")); + fail_unless(eina_value_list_append(value, "k-s")); + + str = eina_value_to_string(value); + fail_unless(str != NULL); + fail_unless(strcmp(str, "[Enlightenment.org, X11, Pants, on!!!, k-s]") == 0); + free(str); + + eina_value_flush(value); + fail_unless(eina_value_list_setup(value, EINA_VALUE_TYPE_CHAR)); + 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_convert(&other, value)); + str = eina_value_to_string(value); + fail_unless(str != NULL); + fail_unless(strcmp(str, "[100]") == 0); + free(str); + + fail_unless(eina_value_list_set(value, 0, 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) { @@ -1034,4 +1169,5 @@ eina_test_value(TCase *tc) tcase_add_test(tc, eina_value_test_convert_uchar); // TODO: other converters... tcase_add_test(tc, eina_value_test_array); + tcase_add_test(tc, eina_value_test_list); }