From: barbieri Date: Thu, 12 Jan 2012 22:58:31 +0000 (+0000) Subject: eina_value: add struct type. X-Git-Tag: 2.0_alpha~35^2~81 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=7bb04172dff384d7bd48e393e35d95ab9dd08e6e;p=framework%2Fuifw%2Feina.git eina_value: add struct type. efficient storage with named access, can specify compare, alloc, free and other operations for even better management. no changelog/news as this is under eina_value, all new for 1.2 release. git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/trunk/eina@67155 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33 --- diff --git a/src/include/eina_inline_value.x b/src/include/eina_inline_value.x index 469fd50..59ec315 100644 --- a/src/include/eina_inline_value.x +++ b/src/include/eina_inline_value.x @@ -944,14 +944,14 @@ eina_value_list_vset(Eina_Value *value, unsigned int position, va_list args) static inline Eina_Bool eina_value_list_vget(const Eina_Value *value, unsigned int position, va_list args) { - Eina_Value_List *desc; + const 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_List *)eina_value_memory_get(value); + desc = (const Eina_Value_List *)eina_value_memory_get(value); if (!desc) return EINA_FALSE; @@ -1120,13 +1120,13 @@ eina_value_list_pset(Eina_Value *value, unsigned int position, const void *ptr) static inline Eina_Bool eina_value_list_pget(const Eina_Value *value, unsigned int position, void *ptr) { - Eina_Value_List *desc; + const 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_List *)eina_value_memory_get(value); + desc = (const Eina_Value_List *)eina_value_memory_get(value); if (!desc) return EINA_FALSE; @@ -1316,14 +1316,14 @@ eina_value_hash_vset(Eina_Value *value, const char *key, va_list args) static inline Eina_Bool eina_value_hash_vget(const Eina_Value *value, const char *key, va_list args) { - Eina_Value_Hash *desc; + const 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_Hash *)eina_value_memory_get(value); + desc = (const Eina_Value_Hash *)eina_value_memory_get(value); if (!desc) return EINA_FALSE; @@ -1403,13 +1403,13 @@ eina_value_hash_pset(Eina_Value *value, const char *key, const void *ptr) static inline Eina_Bool eina_value_hash_pget(const Eina_Value *value, const char *key, void *ptr) { - Eina_Value_Hash *desc; + const 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_Hash *)eina_value_memory_get(value); + desc = (const Eina_Value_Hash *)eina_value_memory_get(value); if (!desc) return EINA_FALSE; @@ -1422,6 +1422,172 @@ eina_value_hash_pget(const Eina_Value *value, const char *key, void *ptr) } #undef EINA_VALUE_TYPE_HASH_CHECK_RETURN_VAL +#define EINA_VALUE_TYPE_STRUCT_CHECK_RETURN_VAL(value, retval) \ + EINA_SAFETY_ON_NULL_RETURN_VAL(value, retval); \ + EINA_SAFETY_ON_FALSE_RETURN_VAL(value->type == EINA_VALUE_TYPE_STRUCT, retval) + +/** + * @brief Find member of struct + * @since 1.2 + * @internal + */ +EAPI const Eina_Value_Struct_Member *eina_value_struct_member_find(const Eina_Value_Struct *st, const char *name) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT; + +static inline Eina_Bool +eina_value_struct_setup(Eina_Value *value, const Eina_Value_Struct_Desc *sdesc) +{ + Eina_Value_Struct desc = {sdesc, NULL}; + if (!eina_value_setup(value, EINA_VALUE_TYPE_STRUCT)) + return EINA_FALSE; + if (!eina_value_pset(value, &desc)) + { + eina_value_flush(value); + return EINA_FALSE; + } + return EINA_TRUE; +} + +static inline void * +eina_value_struct_member_memory_get(const Eina_Value_Struct *st, const Eina_Value_Struct_Member *member) +{ + unsigned char *base = (unsigned char *)st->memory; + if (!base) return NULL; + return base + member->offset; +} + +static inline Eina_Bool +eina_value_struct_vset(Eina_Value *value, const char *name, va_list args) +{ + const Eina_Value_Struct_Member *member; + Eina_Value_Struct *st; + void *mem; + + EINA_VALUE_TYPE_STRUCT_CHECK_RETURN_VAL(value, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE); + st = (Eina_Value_Struct *)eina_value_memory_get(value); + if (!st) + return EINA_FALSE; + member = eina_value_struct_member_find(st, name); + if (!member) + return EINA_FALSE; + mem = eina_value_struct_member_memory_get(st, member); + if (!mem) + return EINA_FALSE; + + eina_value_type_flush(member->type, mem); + if (!eina_value_type_setup(member->type, mem)) goto error_setup; + if (!eina_value_type_vset(member->type, mem, args)) goto error_set; + return EINA_TRUE; + + error_set: + eina_value_type_flush(member->type, mem); + error_setup: + return EINA_FALSE; +} + +static inline Eina_Bool +eina_value_struct_vget(const Eina_Value *value, const char *name, va_list args) +{ + const Eina_Value_Struct_Member *member; + const Eina_Value_Struct *st; + const void *mem; + void *ptr; + Eina_Bool ret; + + EINA_VALUE_TYPE_STRUCT_CHECK_RETURN_VAL(value, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE); + st = (const Eina_Value_Struct *)eina_value_memory_get(value); + if (!st) + return EINA_FALSE; + member = eina_value_struct_member_find(st, name); + if (!member) + return EINA_FALSE; + mem = eina_value_struct_member_memory_get(st, member); + if (!mem) + return EINA_FALSE; + + ptr = va_arg(args, void *); + ret = eina_value_type_pget(member->type, mem, ptr); + return ret; +} + +static inline Eina_Bool +eina_value_struct_set(Eina_Value *value, const char *name, ...) +{ + va_list args; + Eina_Bool ret; + va_start(args, name); + ret = eina_value_struct_vset(value, name, args); + va_end(args); + return ret; +} + +static inline Eina_Bool +eina_value_struct_get(const Eina_Value *value, const char *name, ...) +{ + va_list args; + Eina_Bool ret; + va_start(args, name); + ret = eina_value_struct_vget(value, name, args); + va_end(args); + return ret; +} + +static inline Eina_Bool +eina_value_struct_pset(Eina_Value *value, const char *name, const void *ptr) +{ + const Eina_Value_Struct_Member *member; + Eina_Value_Struct *st; + void *mem; + + EINA_VALUE_TYPE_STRUCT_CHECK_RETURN_VAL(value, 0); + EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE); + st = (Eina_Value_Struct *)eina_value_memory_get(value); + if (!st) + return EINA_FALSE; + member = eina_value_struct_member_find(st, name); + if (!member) + return EINA_FALSE; + mem = eina_value_struct_member_memory_get(st, member); + if (!mem) + return EINA_FALSE; + + eina_value_type_flush(member->type, mem); + if (!eina_value_type_setup(member->type, mem)) goto error_setup; + if (!eina_value_type_pset(member->type, mem, ptr)) goto error_set; + return EINA_TRUE; + + error_set: + eina_value_type_flush(member->type, mem); + error_setup: + return EINA_FALSE; +} + +static inline Eina_Bool +eina_value_struct_pget(const Eina_Value *value, const char *name, void *ptr) +{ + const Eina_Value_Struct_Member *member; + const Eina_Value_Struct *st; + const void *mem; + Eina_Bool ret; + + EINA_VALUE_TYPE_STRUCT_CHECK_RETURN_VAL(value, 0); + EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE); + st = (const Eina_Value_Struct *)eina_value_memory_get(value); + if (!st) + return EINA_FALSE; + member = eina_value_struct_member_find(st, name); + if (!member) + return EINA_FALSE; + mem = eina_value_struct_member_memory_get(st, member); + if (!mem) + return EINA_FALSE; + + ret = eina_value_type_pget(member->type, mem, ptr); + return ret; +} +#undef EINA_VALUE_TYPE_STRUCT_CHECK_RETURN_VAL + static inline Eina_Bool eina_value_type_setup(const Eina_Value_Type *type, void *mem) @@ -1460,7 +1626,7 @@ eina_value_type_copy(const Eina_Value_Type *type, const void *src, void *dst) } static inline int -eina_value_type_compare(const Eina_Value_Type *type, const void *a, void *b) +eina_value_type_compare(const Eina_Value_Type *type, const void *a, const void *b) { EINA_SAFETY_ON_FALSE_RETURN_VAL(eina_value_type_check(type), EINA_FALSE); if (!type->compare) diff --git a/src/include/eina_value.h b/src/include/eina_value.h index 7ecf63e..55b465a 100644 --- a/src/include/eina_value.h +++ b/src/include/eina_value.h @@ -302,6 +302,28 @@ EAPI extern const Eina_Value_Type *EINA_VALUE_TYPE_TIMEVAL; EAPI extern const Eina_Value_Type *EINA_VALUE_TYPE_BLOB; /** + * @var EINA_VALUE_TYPE_STRUCT + * + * manages struct type. Use the value get/set for structs: + * @li eina_value_struct_get() and eina_value_struct_set() + * @li eina_value_struct_vget() and eina_value_struct_vset() + * @li eina_value_struct_pget() and eina_value_struct_pset() + * + * eina_value_set() takes an #Eina_Value_Struct where just @c desc is + * used. If there is an @c memory, it will be adopted and its contents + * must be properly configurable as @c desc expects. eina_value_pset() + * takes a pointer to an #Eina_Value_Struct. For your convenience, use + * eina_value_struct_setup(). + * + * eina_value_get() and eina_value_pget() takes a pointer to + * #Eina_Value_Struct, it's an exact copy of the current structure in + * use by value, no copies are done. + * + * @since 1.2 + */ +EAPI extern const Eina_Value_Type *EINA_VALUE_TYPE_STRUCT; + +/** * @var EINA_ERROR_VALUE_FAILED * Error identifier corresponding to value check failure. * @@ -464,6 +486,7 @@ static inline int eina_value_compare(const Eina_Value *a, * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob + * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct * * @code * Eina_Value *value = eina_value_new(EINA_VALUE_TYPE_INT); @@ -524,6 +547,7 @@ static inline Eina_Bool eina_value_set(Eina_Value *value, * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash* * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval* * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob* + * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct* * * @code * Eina_Value *value = eina_value_new(EINA_VALUE_TYPE_INT); @@ -626,6 +650,7 @@ static inline Eina_Bool eina_value_vget(const Eina_Value *value, * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash* * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval* * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob* + * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct* * * @note the pointer contents are written using the size defined by * type. It can be larger than void* or uint64_t. @@ -691,6 +716,7 @@ static inline Eina_Bool eina_value_pset(Eina_Value *value, * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash* * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval* * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob* + * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob* * * @code * Eina_Value *value = eina_value_new(EINA_VALUE_TYPE_INT); @@ -898,6 +924,7 @@ static inline Eina_Bool eina_value_array_remove(Eina_Value *value, * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob + * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct * * @code * Eina_Value *value = eina_value_array_new(EINA_VALUE_TYPE_INT, 0); @@ -958,6 +985,7 @@ static inline Eina_Bool eina_value_array_set(Eina_Value *value, * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash* * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval* * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob* + * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct* * * @code * Eina_Value *value = eina_value_array_new(EINA_VALUE_TYPE_INT, 0); @@ -1006,6 +1034,7 @@ static inline Eina_Bool eina_value_array_get(const Eina_Value *value, * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob + * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct * * @code * Eina_Value *value = eina_value_array_new(EINA_VALUE_TYPE_INT, 0); @@ -1060,6 +1089,7 @@ static inline Eina_Bool eina_value_array_insert(Eina_Value *value, * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob + * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct * * @code * Eina_Value *value = eina_value_array_new(EINA_VALUE_TYPE_INT, 0); @@ -1200,6 +1230,7 @@ static inline Eina_Bool eina_value_array_vappend(Eina_Value *value, * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash* * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval* * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob* + * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct* * * @note the pointer contents are written using the size defined by * type. It can be larger than void* or uint64_t. @@ -1264,6 +1295,7 @@ static inline Eina_Bool eina_value_array_pset(Eina_Value *value, * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash* * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval* * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob* + * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct* * * @code * Eina_Value *value = eina_value_array_new(EINA_VALUE_TYPE_INT, 0); @@ -1313,6 +1345,7 @@ static inline Eina_Bool eina_value_array_pget(const Eina_Value *value, * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash* * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval* * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob* + * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct* * * @note the pointer contents are written using the size defined by * type. It can be larger than void* or uint64_t. @@ -1370,6 +1403,7 @@ static inline Eina_Bool eina_value_array_pinsert(Eina_Value *value, * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash* * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval* * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob* + * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct* * * @note the pointer contents are written using the size defined by * type. It can be larger than void* or uint64_t. @@ -1520,6 +1554,7 @@ static inline Eina_Bool eina_value_list_remove(Eina_Value *value, * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob + * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct * * @code * Eina_Value *value = eina_value_list_new(EINA_VALUE_TYPE_INT); @@ -1579,6 +1614,7 @@ static inline Eina_Bool eina_value_list_set(Eina_Value *value, * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash* * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval* * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob* + * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct* * * @code * Eina_Value *value = eina_value_list_new(EINA_VALUE_TYPE_INT); @@ -1626,6 +1662,7 @@ static inline Eina_Bool eina_value_list_get(const Eina_Value *value, * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob + * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct * * @code * Eina_Value *value = eina_value_list_new(EINA_VALUE_TYPE_INT); @@ -1679,6 +1716,7 @@ static inline Eina_Bool eina_value_list_insert(Eina_Value *value, * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob + * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct * * @code * Eina_Value *value = eina_value_list_new(EINA_VALUE_TYPE_INT); @@ -1818,6 +1856,7 @@ static inline Eina_Bool eina_value_list_vappend(Eina_Value *value, * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash* * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval* * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob* + * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct* * * @note the pointer contents are written using the size defined by * type. It can be larger than void* or uint64_t. @@ -1881,6 +1920,7 @@ static inline Eina_Bool eina_value_list_pset(Eina_Value *value, * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash* * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval* * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob* + * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct* * * @code * Eina_Value *value = eina_value_list_new(EINA_VALUE_TYPE_INT); @@ -1929,6 +1969,7 @@ static inline Eina_Bool eina_value_list_pget(const Eina_Value *value, * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash* * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval* * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob* + * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct* * * @note the pointer contents are written using the size defined by * type. It can be larger than void* or uint64_t. @@ -1985,6 +2026,7 @@ static inline Eina_Bool eina_value_list_pinsert(Eina_Value *value, * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash* * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval* * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob* + * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct* * * @note the pointer contents are written using the size defined by * type. It can be larger than void* or uint64_t. @@ -2118,7 +2160,7 @@ static inline Eina_Bool eina_value_hash_del(Eina_Value *value, * @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 + * The variable argument is dependent on chosen subtype. The list for * basic types: * * @li EINA_VALUE_TYPE_UCHAR: unsigned char @@ -2138,6 +2180,7 @@ static inline Eina_Bool eina_value_hash_del(Eina_Value *value, * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval* * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob* + * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct* * * @code * Eina_Value *value = eina_value_hash_new(EINA_VALUE_TYPE_INT, 0); @@ -2170,7 +2213,7 @@ static inline Eina_Bool eina_value_hash_set(Eina_Value *value, * stored inside the object. There shouldn't be any memory allocation, * thus the contents should @b not be freed. * - * The variable argument is dependent on chosen subtype. The hash for + * The variable argument is dependent on chosen subtype. The list for * basic types: * * @li EINA_VALUE_TYPE_UCHAR: unsigned char* @@ -2190,6 +2233,7 @@ static inline Eina_Bool eina_value_hash_set(Eina_Value *value, * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash* * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval* * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob* + * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct* * * @code * Eina_Value *value = eina_value_hash_new(EINA_VALUE_TYPE_INT, 0); @@ -2255,7 +2299,7 @@ static inline Eina_Bool eina_value_hash_vget(const Eina_Value *value, * @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 + * The pointer type is dependent on chosen value type. The list for * basic types: * * @li EINA_VALUE_TYPE_UCHAR: unsigned char* @@ -2275,6 +2319,7 @@ static inline Eina_Bool eina_value_hash_vget(const Eina_Value *value, * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash* * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval* * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob* + * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct* * * @note the pointer contents are written using the size defined by * type. It can be larger than void* or uint64_t. @@ -2310,7 +2355,7 @@ static inline Eina_Bool eina_value_hash_pset(Eina_Value *value, * object. There shouldn't be any memory allocation, thus the contents * should @b not be freed. * - * The pointer type is dependent on chosen value type. The hash for + * The pointer type is dependent on chosen value type. The list for * basic types: * * @li EINA_VALUE_TYPE_UCHAR: unsigned char* @@ -2330,6 +2375,7 @@ static inline Eina_Bool eina_value_hash_pset(Eina_Value *value, * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash* * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval* * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob* + * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct* * * @code * Eina_Value *value = eina_value_hash_new(EINA_VALUE_TYPE_INT, 0); @@ -2415,6 +2461,475 @@ struct _Eina_Value_Blob */ /** + * @defgroup Eina_Value_Struct_Group Generic Value Struct management + * + * @{ + */ + +/** + * @typedef Eina_Value_Struct_Operations + * How to manage struct. Any @c NULL callback is ignored. + * @since 1.2 + */ +typedef struct _Eina_Value_Struct_Operations Eina_Value_Struct_Operations; + +/** + * @typedef Eina_Value_Struct_Member + * Describes a single member of struct. + * @since 1.2 + */ +typedef struct _Eina_Value_Struct_Member Eina_Value_Struct_Member; + +/** + * @typedef Eina_Value_Struct_Desc + * Describes the struct by listing its size, members and operations. + * @since 1.2 + */ +typedef struct _Eina_Value_Struct_Desc Eina_Value_Struct_Desc; + +/** + * @typedef Eina_Value_Struct + * @since 1.2 + */ +typedef struct _Eina_Value_Struct Eina_Value_Struct; + +/** + * @struct _Eina_Value_Struct_Operations + * How to manage struct. Any @c NULL callback is ignored. + * @since 1.2 + */ +struct _Eina_Value_Struct_Operations +{ +#define EINA_VALUE_STRUCT_OPERATIONS_VERSION (1) + unsigned int version; /**< must be EINA_VALUE_STRUCT_OPERATIONS_VERSION */ + void *(*alloc)(const Eina_Value_Struct_Operations *ops, const Eina_Value_Struct_Desc *desc); + void (*free)(const Eina_Value_Struct_Operations *ops, const Eina_Value_Struct_Desc *desc, void *memory); + void *(*copy)(const Eina_Value_Struct_Operations *ops, const Eina_Value_Struct_Desc *desc, const void *memory); + int (*compare)(const Eina_Value_Struct_Operations *ops, const Eina_Value_Struct_Desc *desc, const void *data1, const void *data2); + const Eina_Value_Struct_Member *(*find_member)(const Eina_Value_Struct_Operations *ops, const Eina_Value_Struct_Desc *desc, const char *name); /**< replace the function to find description for member. For huge structures consider using binary search, stringshared, hash or gperf. The default function does linear search using strcmp(). */ +}; + +/** + * @var EINA_VALUE_STRUCT_OPERATIONS_BINSEARCH + * + * Assumes @c members is sorted by name and applies binary search for + * names. + * + * Ideally the @c member_count field is set to speed it up. + * + * No other methods are set (alloc, free, copy, compare), then it uses + * the default operations. + */ +EAPI extern const Eina_Value_Struct_Operations *EINA_VALUE_STRUCT_OPERATIONS_BINSEARCH; + +/** + * @var EINA_VALUE_STRUCT_OPERATIONS_STRINGSHARE + * + * Assumes @c members name are stringshared and can be compared for + * equality without using its contents (simple pointer comparison). + * + * Ideally the search @c name will be stringshared as well, but it + * will do a second loop with a forced stringshare if it did not find + * the member. + * + * No other methods are set (alloc, free, copy, compare), then it uses + * the default operations. + */ +EAPI extern const Eina_Value_Struct_Operations *EINA_VALUE_STRUCT_OPERATIONS_STRINGSHARE; + +/** + * @struct _Eina_Value_Struct_Member + * @since 1.2 + */ +struct _Eina_Value_Struct_Member +{ + const char *name; + const Eina_Value_Type *type; + unsigned int offset; +}; + +/** + * @struct _Eina_Value_Struct_Desc + * @since 1.2 + */ +struct _Eina_Value_Struct_Desc +{ +#define EINA_VALUE_STRUCT_DESC_VERSION (1) + unsigned int version; /**< must be EINA_VALUE_STRUCT_DESC_VERSION */ + const Eina_Value_Struct_Operations *ops; /**< operations, if @c NULL defaults will be used. You may use operations to optimize member lookup using binary search or gperf hash. */ + const Eina_Value_Struct_Member *members; /**< array of member descriptions, if @c member_count is zero, then it must be @c NULL terminated. */ + unsigned int member_count; /**< if > 0, specifies number of members. If zero then @c members must be NULL terminated. */ + unsigned int size; /**< byte size to allocate, may be bigger than sum of members */ +}; + +/** + * @struct _Eina_Value_Struct + * @since 1.2 + */ +struct _Eina_Value_Struct +{ + const Eina_Value_Struct_Desc *desc; + void *memory; +}; + +/** + * @brief Create generic value storage of type struct. + * @param desc how to manage this struct members. + * @return The new value or @c NULL on failure. + * + * Create a new generic value storage of type struct. The members are + * managed using the description specified by @a desc. + * + * On failure, @c NULL is returned and #EINA_ERROR_OUT_OF_MEMORY or + * #EINA_ERROR_VALUE_FAILED is set. + * + * @note this creates from mempool and then uses + * eina_value_struct_setup(). + * + * @see eina_value_free() + * @see eina_value_struct_setup() + * + * @since 1.2 + */ +EAPI Eina_Value *eina_value_struct_new(const Eina_Value_Struct_Desc *desc) EINA_ARG_NONNULL(1); + +/** + * @brief Initialize generic value storage of type struct. + * @param value value object + * @param desc how to manage this struct members. + * @return #EINA_TRUE on success, #EINA_FALSE otherwise. + * + * Initializes new generic value storage of type struct with the given + * @a desc. + * + * This is the same as calling eina_value_set() with + * #EINA_VALUE_TYPE_STRUCT followed by eina_value_pset() with the + * #Eina_Value_Struct description configured. + * + * @note Existing contents are ignored! If the value was previously used, 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_struct_setup(Eina_Value *value, + const Eina_Value_Struct_Desc *desc) EINA_ARG_NONNULL(1, 2); + +/** + * @brief Set the generic value in an struct member. + * @param value source value object + * @param name name to find the member + * @return #EINA_TRUE on success, #EINA_FALSE otherwise. + * + * The variable argument is dependent on chosen member 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_HASH: Eina_Value_Hash + * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval* + * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob* + * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct* + * + * @code + * struct myst { + * int i; + * char c; + * }; + * const Eina_Value_Struct_Member myst_members[] = { + * {"i", EINA_VALUE_TYPE_INT, 0}, + * {"c", EINA_VALUE_TYPE_CHAR, 4}, + * {NULL, NULL, 0} + * }; + * const Eina_Value_Struct_Desc myst_desc = { + * EINA_VALUE_STRUCT_DESC_VERSION, + * NULL, myst_members, 2, sizeof(struct myst) + * }; + * Eina_Value *value = eina_value_struct_new(&my_desc); + * int x; + * char y; + * + * eina_value_struct_set(value, "i", 5678); + * eina_value_struct_get(value, "i", &x); + * eina_value_struct_set(value, "c", 0xf); + * eina_value_struct_get(value, "c", &y); + * eina_value_free(value); + * @endcode + * + * @see eina_value_struct_get() + * @see eina_value_struct_vset() + * @see eina_value_struct_pset() + * + * @since 1.2 + */ +static inline Eina_Bool eina_value_struct_set(Eina_Value *value, + const char *name, + ...) EINA_ARG_NONNULL(1); + +/** + * @brief Get the generic value from an struct member. + * @param value source value object + * @param name name 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 freed. + * + * The variable argument is dependent on chosen member 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_HASH: Eina_Value_Hash* + * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval* + * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob* + * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct* + * + * @code + * struct myst { + * int i; + * char c; + * }; + * const Eina_Value_Struct_Member myst_members[] = { + * {"i", EINA_VALUE_TYPE_INT, 0}, + * {"c", EINA_VALUE_TYPE_CHAR, 4}, + * {NULL, NULL, 0} + * }; + * const Eina_Value_Struct_Desc myst_desc = { + * EINA_VALUE_STRUCT_DESC_VERSION, + * NULL, myst_members, 2, sizeof(struct myst) + * }; + * Eina_Value *value = eina_value_struct_new(&my_desc); + * int x; + * char y; + * + * eina_value_struct_set(value, "i", 5678); + * eina_value_struct_get(value, "i", &x); + * eina_value_struct_set(value, "c", 0xf); + * eina_value_struct_get(value, "c", &y); + * eina_value_free(value); + * @endcode + * + * @see eina_value_struct_set() + * @see eina_value_struct_vset() + * @see eina_value_struct_pset() + * + * @since 1.2 + */ +static inline Eina_Bool eina_value_struct_get(const Eina_Value *value, + const char *name, + ...) EINA_ARG_NONNULL(1); + +/** + * @brief Set the generic value in an struct member. + * @param value source value object + * @param name name to find the member + * @param args variable argument + * @return #EINA_TRUE on success, #EINA_FALSE otherwise. + * @see eina_value_struct_set() + * @see eina_value_struct_get() + * @see eina_value_struct_pset() + * + * @since 1.2 + */ +static inline Eina_Bool eina_value_struct_vset(Eina_Value *value, + const char *name, + va_list args) EINA_ARG_NONNULL(1); + +/** + * @brief Get the generic value from an struct member. + * @param value source value object + * @param name name 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 freed. + * + * @see eina_value_struct_vset() + * @see eina_value_struct_get() + * @see eina_value_struct_pget() + * + * @since 1.2 + */ +static inline Eina_Bool eina_value_struct_vget(const Eina_Value *value, + const char *name, + va_list args) EINA_ARG_NONNULL(1); + +/** + * @brief Set the generic value in an struct member from pointer. + * @param value source value object + * @param name name 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 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_HASH: Eina_Value_Hash* + * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval* + * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob* + * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct* + * + * @note the pointer contents are written using the size defined by + * type. It can be larger than void* or uint64_t. + * + * @code + * struct myst { + * int i; + * char c; + * }; + * const Eina_Value_Struct_Member myst_members[] = { + * {"i", EINA_VALUE_TYPE_INT, 0}, + * {"c", EINA_VALUE_TYPE_CHAR, 4}, + * {NULL, NULL, 0} + * }; + * const Eina_Value_Struct_Desc myst_desc = { + * EINA_VALUE_STRUCT_DESC_VERSION, + * NULL, myst_members, 2, sizeof(struct myst) + * }; + * Eina_Value *value = eina_value_struct_new(&my_desc); + * int x = 5678; + * char y = 0xf; + * + * eina_value_struct_pset(value, "i", &); + * eina_value_struct_pget(value, "i", &x); + * eina_value_struct_pset(value, "c", &y); + * eina_value_struct_pget(value, "c", &y); + * eina_value_free(value); + * @endcode + * + * @see eina_value_struct_set() + * @see eina_value_struct_get() + * @see eina_value_struct_vset() + * + * @since 1.2 + */ +static inline Eina_Bool eina_value_struct_pset(Eina_Value *value, + const char *name, + const void *ptr) EINA_ARG_NONNULL(1, 3); + +/** + * @brief Get the generic value to pointer from an struct member. + * @param value source value object + * @param name name 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 freed. + * + * 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_HASH: Eina_Value_Hash* + * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval* + * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob* + * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct* + * + * @code + * struct myst { + * int i; + * char c; + * }; + * const Eina_Value_Struct_Member myst_members[] = { + * {"i", EINA_VALUE_TYPE_INT, 0}, + * {"c", EINA_VALUE_TYPE_CHAR, 4}, + * {NULL, NULL, 0} + * }; + * const Eina_Value_Struct_Desc myst_desc = { + * EINA_VALUE_STRUCT_DESC_VERSION, + * NULL, myst_members, 2, sizeof(struct myst) + * }; + * Eina_Value *value = eina_value_struct_new(&my_desc); + * int x = 5678; + * char y = 0xf; + * + * eina_value_struct_pset(value, "i", &); + * eina_value_struct_pget(value, "i", &x); + * eina_value_struct_pset(value, "c", &y); + * eina_value_struct_pget(value, "c", &y); + * eina_value_free(value); + * @endcode + * + * @see eina_value_struct_set() + * @see eina_value_struct_vset() + * @see eina_value_struct_pset() + * + * @since 1.2 + */ +static inline Eina_Bool eina_value_struct_pget(const Eina_Value *value, + const char *name, + void *ptr) EINA_ARG_NONNULL(1, 3); + +/** + * @} + */ + + +/** * @defgroup Eina_Value_Type_Group Generic Value Type management * * @{ @@ -2503,7 +3018,7 @@ static inline Eina_Bool eina_value_type_copy(const Eina_Value_Type *type, const * @return less than zero if a < b, greater than zero if a > b, zero if equal. * @since 1.2 */ -static inline int eina_value_type_compare(const Eina_Value_Type *type, const void *a, void *b); +static inline int eina_value_type_compare(const Eina_Value_Type *type, const void *a, const void *b); /** * @brief Convert memory using type descriptor. diff --git a/src/lib/eina_value.c b/src/lib/eina_value.c index 620098a..0796462 100644 --- a/src/lib/eina_value.c +++ b/src/lib/eina_value.c @@ -3819,6 +3819,497 @@ static const Eina_Value_Type _EINA_VALUE_TYPE_BLOB = { _eina_value_type_blob_pget }; +static int +_eina_value_struct_operations_binsearch_cmp(const void *pa, const void *pb) +{ + const Eina_Value_Struct_Member *a = pa, *b = pb; + return strcmp(a->name, b->name); +} + +static const Eina_Value_Struct_Member * +_eina_value_struct_operations_binsearch_find_member(const Eina_Value_Struct_Operations *ops __UNUSED__, const Eina_Value_Struct_Desc *desc, const char *name) +{ + unsigned int count = desc->member_count; + Eina_Value_Struct_Member search; + if (count == 0) + { + const Eina_Value_Struct_Member *itr = desc->members; + for (; itr->name != NULL; itr++) + count++; + } + + search.name = name; + return bsearch(&search, desc->members, count, + sizeof(Eina_Value_Struct_Member), + _eina_value_struct_operations_binsearch_cmp); +} + +static Eina_Value_Struct_Operations _EINA_VALUE_STRUCT_OPERATIONS_BINSEARCH = { + EINA_VALUE_STRUCT_OPERATIONS_VERSION, + NULL, /* default alloc */ + NULL, /* default free */ + NULL, /* default copy */ + NULL, /* default compare */ + _eina_value_struct_operations_binsearch_find_member +}; + +static const Eina_Value_Struct_Member * +_eina_value_struct_operations_stringshare_find_member(const Eina_Value_Struct_Operations *ops __UNUSED__, const Eina_Value_Struct_Desc *desc, const char *name) +{ + const Eina_Value_Struct_Member *itr = desc->members; + + /* assumes name is stringshared. + * + * we do this because it's the recommended usage pattern, moreover + * we expect to find the member, as users shouldn't look for + * non-existent members! + */ + if (desc->member_count > 0) + { + const Eina_Value_Struct_Member *itr_end = itr + desc->member_count; + for (; itr < itr_end; itr++) + if (itr->name == name) + return itr; + } + else + { + for (; itr->name != NULL; itr++) + if (itr->name == name) + return itr; + } + + name = eina_stringshare_add(name); + eina_stringshare_del(name); /* we'll not use the contents, this is fine */ + /* stringshare and look again */ + if (desc->member_count > 0) + { + const Eina_Value_Struct_Member *itr_end = itr + desc->member_count; + for (; itr < itr_end; itr++) + if (itr->name == name) + return itr; + } + else + { + for (; itr->name != NULL; itr++) + if (itr->name == name) + return itr; + } + + return NULL; +} + +static Eina_Value_Struct_Operations _EINA_VALUE_STRUCT_OPERATIONS_STRINGSHARE = { + EINA_VALUE_STRUCT_OPERATIONS_VERSION, + NULL, /* default alloc */ + NULL, /* default free */ + NULL, /* default copy */ + NULL, /* default compare */ + _eina_value_struct_operations_stringshare_find_member +}; + +static inline const Eina_Value_Struct_Operations * +_eina_value_type_struct_ops_get(const Eina_Value_Struct *st) +{ + if (!st) return NULL; + if (!st->desc) return NULL; + if (!st->desc->ops) return NULL; + EINA_SAFETY_ON_FALSE_RETURN_VAL + (st->desc->ops->version == EINA_VALUE_STRUCT_OPERATIONS_VERSION, NULL); + return st->desc->ops; +} + +EAPI const Eina_Value_Struct_Member * +eina_value_struct_member_find(const Eina_Value_Struct *st, const char *name) +{ + const Eina_Value_Struct_Operations *ops; + const Eina_Value_Struct_Member *itr; + + EINA_SAFETY_ON_NULL_RETURN_VAL(st, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(st->desc, NULL); + + ops = _eina_value_type_struct_ops_get(st); + if ((ops) && (ops->find_member)) + return ops->find_member(ops, st->desc, name); + + itr = st->desc->members; + if (st->desc->member_count) + { + const Eina_Value_Struct_Member *itr_end = itr + st->desc->member_count; + for (; itr < itr_end; itr++) + { + if (strcmp(name, itr->name) == 0) + return itr; + } + return NULL; + } + else + { + for (; itr->name != NULL; itr++) + { + if (strcmp(name, itr->name) == 0) + return itr; + } + return NULL; + } +} + +static Eina_Bool +_eina_value_type_struct_setup(const Eina_Value_Type *type __UNUSED__, void *mem) +{ + memset(mem, 0, sizeof(Eina_Value_Struct)); + return EINA_TRUE; +} + +static Eina_Bool +_eina_value_type_struct_flush_member(const Eina_Value_Struct_Member *member, Eina_Value_Struct *st) +{ + unsigned char *base = st->memory; + return eina_value_type_flush(member->type, base + member->offset); +} + +static Eina_Bool +_eina_value_type_struct_flush(const Eina_Value_Type *type __UNUSED__, void *mem) +{ + const Eina_Value_Struct_Operations *ops; + const Eina_Value_Struct_Member *itr; + Eina_Value_Struct *tmem = mem; + Eina_Bool ret = EINA_TRUE; + + itr = tmem->desc->members; + if (tmem->desc->member_count > 0) + { + const Eina_Value_Struct_Member *itr_end; + itr_end = itr + tmem->desc->member_count; + for (; itr < itr_end; itr++) + ret &= _eina_value_type_struct_flush_member(itr, tmem); + } + else + { + for (; itr->name != NULL; itr++) + ret &= _eina_value_type_struct_flush_member(itr, tmem); + } + + ops = _eina_value_type_struct_ops_get(mem); + if ((ops) && (ops->free)) + ops->free(ops, tmem->desc, tmem->memory); + else + free(tmem->memory); + + return ret; +} + +static Eina_Bool +_eina_value_type_struct_copy_member(const Eina_Value_Struct_Member *member, const Eina_Value_Struct *s, Eina_Value_Struct *d) +{ + const unsigned char *base_s = s->memory; + unsigned char *base_d = d->memory; + return eina_value_type_copy(member->type, + base_s + member->offset, + base_d + member->offset); +} + +static Eina_Bool +_eina_value_type_struct_copy(const Eina_Value_Type *type __UNUSED__, const void *src, void *dst) +{ + const Eina_Value_Struct_Operations *ops; + const Eina_Value_Struct_Member *itr; + const Eina_Value_Struct *s = src; + Eina_Value_Struct *d = dst; + + *d = *s; + + ops = _eina_value_type_struct_ops_get(src); + if ((ops) && (ops->copy)) + { + d->memory = ops->copy(ops, s->desc, s->memory); + if (d->memory == NULL) + return EINA_FALSE; + return EINA_TRUE; + } + + d->memory = malloc(s->desc->size); + if (!d->memory) + { + eina_error_set(EINA_ERROR_OUT_OF_MEMORY); + return EINA_FALSE; + } + + itr = s->desc->members; + if (s->desc->member_count > 0) + { + const Eina_Value_Struct_Member *itr_end = itr + s->desc->member_count; + for (; itr < itr_end; itr++) + if (!_eina_value_type_struct_copy_member(itr, s, d)) + goto error; + } + else + { + for (; itr->name != NULL; itr++) + if (!_eina_value_type_struct_copy_member(itr, s, d)) + goto error; + } + + + return EINA_TRUE; + + error: + itr--; + for (; itr >= s->desc->members; itr--) + _eina_value_type_struct_flush_member(itr, d); + free(d->memory); + return EINA_FALSE; +} + +static inline int +_eina_value_type_struct_compare_member(const Eina_Value_Struct_Member *member, const Eina_Value_Struct *ta, const Eina_Value_Struct *tb) +{ + const unsigned char *base_a = ta->memory; + const unsigned char *base_b = tb->memory; + return eina_value_type_compare(member->type, + base_a + member->offset, + base_b + member->offset); +} + +static int +_eina_value_type_struct_compare(const Eina_Value_Type *type __UNUSED__, const void *a, const void *b) +{ + const Eina_Value_Struct_Operations *ops = _eina_value_type_struct_ops_get(a); + const Eina_Value_Struct *ta = a, *tb = b; + const Eina_Value_Struct_Member *itr; + int cmp = 0; + + if (ta->desc != tb->desc) + { + eina_error_set(EINA_ERROR_VALUE_FAILED); + return -1; + } + if (ta->desc->ops != tb->desc->ops) + { + eina_error_set(EINA_ERROR_VALUE_FAILED); + return -1; + } + if ((!ta->memory) && (!tb->memory)) + return 0; + else if (!ta->memory) + return -1; + else if (!tb->memory) + return 1; + + if ((ops) && (ops->compare)) + return ops->compare(ops, ta->desc, ta->memory, tb->memory); + + itr = ta->desc->members; + if (ta->desc->member_count > 0) + { + const Eina_Value_Struct_Member *itr_end = itr + ta->desc->member_count; + for (; (cmp == 0) && (itr < itr_end); itr++) + cmp = _eina_value_type_struct_compare_member(itr, ta, tb); + } + else + { + for (; (cmp == 0) && (itr->name != NULL); itr++) + cmp = _eina_value_type_struct_compare_member(itr, ta, tb); + } + return cmp; +} + +static void +_eina_value_type_struct_convert_to_string_member(const Eina_Value_Struct *st, const Eina_Value_Struct_Member *member, Eina_Strbuf *str) +{ + const unsigned char *p = st->memory; + Eina_Bool first = st->desc->members == member; + Eina_Bool r = EINA_FALSE; + + if (first) eina_strbuf_append_printf(str, "%s: ", member->name); + else eina_strbuf_append_printf(str, ", %s: ", member->name); + + if ((member->type) && (member->type->convert_to)) + { + const Eina_Value_Type *type = member->type; + char *conv = NULL; + + r = eina_value_type_convert_to(type, EINA_VALUE_TYPE_STRING, + p + member->offset, &conv); + if (r) + { + eina_strbuf_append(str, conv); + free(conv); + } + } + + if (!r) + eina_strbuf_append_char(str, '?'); +} + +static Eina_Bool +_eina_value_type_struct_convert_to(const Eina_Value_Type *type __UNUSED__, const Eina_Value_Type *convert, const void *type_mem, void *convert_mem) +{ + const Eina_Value_Struct *tmem = type_mem; + + eina_error_set(0); + if (convert == EINA_VALUE_TYPE_STRINGSHARE || + convert == EINA_VALUE_TYPE_STRING) + { + Eina_Strbuf *str = eina_strbuf_new(); + const char *s; + Eina_Bool ret; + + if (!tmem->memory) eina_strbuf_append(str, "{}"); + else + { + const Eina_Value_Struct_Member *itr = tmem->desc->members; + + eina_strbuf_append_char(str, '{'); + + if (tmem->desc->member_count > 0) + { + const Eina_Value_Struct_Member *itr_end; + + itr_end = itr + tmem->desc->member_count; + for (; itr < itr_end; itr++) + _eina_value_type_struct_convert_to_string_member + (tmem, itr, str); + } + else + { + for (; itr->name != NULL; itr++) + _eina_value_type_struct_convert_to_string_member + (tmem, itr, str); + } + + eina_strbuf_append_char(str, '}'); + } + s = eina_strbuf_string_get(str); + ret = eina_value_type_pset(convert, convert_mem, &s); + eina_strbuf_free(str); + return ret; + } + else + { + eina_error_set(EINA_ERROR_VALUE_FAILED); + return EINA_FALSE; + } +} + +static Eina_Bool +_eina_value_type_struct_desc_check(const Eina_Value_Struct_Desc *desc) +{ + unsigned int minsize = 0; + const Eina_Value_Struct_Member *itr; + + EINA_SAFETY_ON_NULL_RETURN_VAL(desc, EINA_FALSE); + EINA_SAFETY_ON_FALSE_RETURN_VAL + (desc->version == EINA_VALUE_STRUCT_DESC_VERSION, EINA_FALSE); + + itr = desc->members; + if (desc->member_count > 0) + { + const Eina_Value_Struct_Member *itr_end = itr + desc->member_count; + for (; itr < itr_end; itr++) + { + unsigned int member_end; + + EINA_SAFETY_ON_FALSE_RETURN_VAL + (eina_value_type_check(itr->type), EINA_FALSE); + EINA_SAFETY_ON_FALSE_RETURN_VAL + (itr->type->value_size > 0, EINA_FALSE); + + member_end = itr->offset + itr->type->value_size; + if (minsize < member_end) + minsize = member_end; + } + } + else + { + for (; itr->name != NULL; itr++) + { + unsigned int member_end; + + EINA_SAFETY_ON_FALSE_RETURN_VAL + (eina_value_type_check(itr->type), EINA_FALSE); + EINA_SAFETY_ON_FALSE_RETURN_VAL + (itr->type->value_size > 0, EINA_FALSE); + + member_end = itr->offset + itr->type->value_size; + if (minsize < member_end) + minsize = member_end; + } + } + + EINA_SAFETY_ON_FALSE_RETURN_VAL(minsize > 0, EINA_FALSE); + EINA_SAFETY_ON_FALSE_RETURN_VAL(desc->size >= minsize, EINA_FALSE); + return EINA_TRUE; +} + +static Eina_Bool +_eina_value_type_struct_pset(const Eina_Value_Type *type __UNUSED__, void *mem, const void *ptr) +{ + const Eina_Value_Struct_Operations *ops = _eina_value_type_struct_ops_get(mem); + Eina_Value_Struct *tmem = mem; + const Eina_Value_Struct *desc = ptr; + + if (!_eina_value_type_struct_desc_check(desc->desc)) + { + eina_error_set(EINA_ERROR_VALUE_FAILED); + return EINA_FALSE; + } + + if ((ops) && (ops->free)) + ops->free(ops, tmem->desc, tmem->memory); + else + free(tmem->memory); + + *tmem = *desc; + + ops = _eina_value_type_struct_ops_get(desc); + if (!tmem->memory) + { + if ((ops) && (ops->alloc)) + tmem->memory = ops->alloc(ops, tmem->desc); + else + tmem->memory = malloc(tmem->desc->size); + + if (!tmem->memory) + { + eina_error_set(EINA_ERROR_OUT_OF_MEMORY); + return EINA_FALSE; + } + } + + eina_error_set(0); + return EINA_TRUE; +} + +static Eina_Bool +_eina_value_type_struct_vset(const Eina_Value_Type *type, void *mem, va_list args) +{ + const Eina_Value_Struct desc = va_arg(args, Eina_Value_Struct); + _eina_value_type_struct_pset(type, mem, &desc); + return EINA_TRUE; +} + +static Eina_Bool +_eina_value_type_struct_pget(const Eina_Value_Type *type __UNUSED__, const void *mem, void *ptr) +{ + memcpy(ptr, mem, sizeof(Eina_Value_Struct)); + return EINA_TRUE; +} + +static const Eina_Value_Type _EINA_VALUE_TYPE_STRUCT = { + EINA_VALUE_TYPE_VERSION, + sizeof(Eina_Value_Struct), + "Eina_Value_Struct", + _eina_value_type_struct_setup, + _eina_value_type_struct_flush, + _eina_value_type_struct_copy, + _eina_value_type_struct_compare, + _eina_value_type_struct_convert_to, + NULL, /* no convert from */ + _eina_value_type_struct_vset, + _eina_value_type_struct_pset, + _eina_value_type_struct_pget +}; + /* keep all basic types inlined in an array so we can compare if it's * a basic type using pointer arithmetic. * @@ -4249,9 +4740,13 @@ eina_value_init(void) EINA_VALUE_TYPE_HASH = &_EINA_VALUE_TYPE_HASH; EINA_VALUE_TYPE_TIMEVAL = &_EINA_VALUE_TYPE_TIMEVAL; EINA_VALUE_TYPE_BLOB = &_EINA_VALUE_TYPE_BLOB; + EINA_VALUE_TYPE_STRUCT = &_EINA_VALUE_TYPE_STRUCT; EINA_VALUE_BLOB_OPERATIONS_MALLOC = &_EINA_VALUE_BLOB_OPERATIONS_MALLOC; + EINA_VALUE_STRUCT_OPERATIONS_BINSEARCH = &_EINA_VALUE_STRUCT_OPERATIONS_BINSEARCH; + EINA_VALUE_STRUCT_OPERATIONS_STRINGSHARE = &_EINA_VALUE_STRUCT_OPERATIONS_STRINGSHARE; + return EINA_TRUE; on_init_fail_hash: @@ -4326,9 +4821,13 @@ EAPI const Eina_Value_Type *EINA_VALUE_TYPE_LIST = NULL; EAPI const Eina_Value_Type *EINA_VALUE_TYPE_HASH = NULL; EAPI const Eina_Value_Type *EINA_VALUE_TYPE_TIMEVAL = NULL; EAPI const Eina_Value_Type *EINA_VALUE_TYPE_BLOB = NULL; +EAPI const Eina_Value_Type *EINA_VALUE_TYPE_STRUCT = NULL; EAPI const Eina_Value_Blob_Operations *EINA_VALUE_BLOB_OPERATIONS_MALLOC = NULL; +EAPI const Eina_Value_Struct_Operations *EINA_VALUE_STRUCT_OPERATIONS_BINSEARCH = NULL; +EAPI const Eina_Value_Struct_Operations *EINA_VALUE_STRUCT_OPERATIONS_STRINGSHARE = NULL; + EAPI Eina_Error EINA_ERROR_VALUE_FAILED = 0; EAPI const unsigned int eina_prime_table[] = @@ -4445,13 +4944,13 @@ eina_value_array_new(const Eina_Value_Type *subtype, unsigned int step) EINA_SAFETY_ON_FALSE_RETURN_VAL(eina_value_type_check(subtype), EINA_FALSE); - value = calloc(1, sizeof(Eina_Value)); + value = eina_mempool_malloc(_eina_value_mp, sizeof(Eina_Value));; if (!value) return NULL; if (!eina_value_array_setup(value, subtype, step)) { - free(value); + eina_mempool_free(_eina_value_mp, value); return NULL; } @@ -4465,13 +4964,13 @@ eina_value_list_new(const Eina_Value_Type *subtype) EINA_SAFETY_ON_FALSE_RETURN_VAL(eina_value_type_check(subtype), EINA_FALSE); - value = calloc(1, sizeof(Eina_Value)); + value = eina_mempool_malloc(_eina_value_mp, sizeof(Eina_Value));; if (!value) return NULL; if (!eina_value_list_setup(value, subtype)) { - free(value); + eina_mempool_free(_eina_value_mp, value); return NULL; } @@ -4485,13 +4984,31 @@ eina_value_hash_new(const Eina_Value_Type *subtype, unsigned int buckets_power_s EINA_SAFETY_ON_FALSE_RETURN_VAL(eina_value_type_check(subtype), EINA_FALSE); - value = calloc(1, sizeof(Eina_Value)); + value = eina_mempool_malloc(_eina_value_mp, sizeof(Eina_Value));; if (!value) return NULL; if (!eina_value_hash_setup(value, subtype, buckets_power_size)) { - free(value); + eina_mempool_free(_eina_value_mp, value); + return NULL; + } + + return value; +} + +EAPI Eina_Value * +eina_value_struct_new(const Eina_Value_Struct_Desc *desc) +{ + Eina_Value *value; + + value = eina_mempool_malloc(_eina_value_mp, sizeof(Eina_Value));; + if (!value) + return NULL; + + if (!eina_value_struct_setup(value, desc)) + { + eina_mempool_free(_eina_value_mp, value); return NULL; } diff --git a/src/tests/eina_test_value.c b/src/tests/eina_test_value.c index 2a81994..bdf279f 100644 --- a/src/tests/eina_test_value.c +++ b/src/tests/eina_test_value.c @@ -1538,6 +1538,180 @@ START_TEST(eina_value_test_blob) } END_TEST + +START_TEST(eina_value_test_struct) +{ + struct mybigst { + int a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, x; + }; +#define EINA_VALUE_STRUCT_MEMBER(eina_value_type, type, member) \ + {#member, eina_value_type, offsetof(type, member)} +#define EINA_VALUE_STRUCT_MEMBER_SENTINEL {NULL, NULL, 0} + const Eina_Value_Struct_Member mybigst_members[] = { + EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_INT, struct mybigst, a), + EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_INT, struct mybigst, b), + EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_INT, struct mybigst, c), + EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_INT, struct mybigst, d), + EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_INT, struct mybigst, e), + EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_INT, struct mybigst, f), + EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_INT, struct mybigst, g), + EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_INT, struct mybigst, h), + EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_INT, struct mybigst, i), + EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_INT, struct mybigst, j), + EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_INT, struct mybigst, k), + EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_INT, struct mybigst, l), + EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_INT, struct mybigst, m), + EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_INT, struct mybigst, n), + EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_INT, struct mybigst, o), + EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_INT, struct mybigst, p), + EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_INT, struct mybigst, q), + EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_INT, struct mybigst, r), + EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_INT, struct mybigst, s), + EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_INT, struct mybigst, t), + EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_INT, struct mybigst, u), + EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_INT, struct mybigst, v), + EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_INT, struct mybigst, x), + EINA_VALUE_STRUCT_MEMBER_SENTINEL + }; + const Eina_Value_Struct_Desc mybigst_desc = { + EINA_VALUE_STRUCT_DESC_VERSION, + EINA_VALUE_STRUCT_OPERATIONS_BINSEARCH, + mybigst_members, 23, sizeof(struct mybigst) + }; + struct myst { + int i; + char c; + }; + const Eina_Value_Struct_Member myst_members[] = { + {"i", EINA_VALUE_TYPE_INT, 0}, + {"c", EINA_VALUE_TYPE_CHAR, 4}, + {NULL, NULL, 0} + }; + const Eina_Value_Struct_Desc myst_desc = { + EINA_VALUE_STRUCT_DESC_VERSION, + NULL, myst_members, 2, sizeof(struct myst) + }; + Eina_Value *value, other; + int i; + char c; + char *str; + + eina_init(); + + value = eina_value_struct_new(&myst_desc); + fail_unless(value != NULL); + + fail_unless(eina_value_struct_set(value, "i", 5678)); + fail_unless(eina_value_struct_set(value, "c", 0xf)); + + fail_unless(eina_value_struct_get(value, "i", &i)); + fail_unless(i == 5678); + fail_unless(eina_value_struct_get(value, "c", &c)); + fail_unless(c == 0xf); + + str = eina_value_to_string(value); + fail_unless(str != NULL); + fail_unless(strcmp(str, "{i: 5678, c: 15}") == 0); + free(str); + + fail_if(eina_value_struct_get(value, "x", 1234)); + + i = 0x11223344; + fail_unless(eina_value_struct_pset(value, "i", &i)); + i = -1; + fail_unless(eina_value_struct_pget(value, "i", &i)); + fail_unless(i == 0x11223344); + + fail_unless(eina_value_copy(value, &other)); + str = eina_value_to_string(&other); + fail_unless(str != NULL); + fail_unless(strcmp(str, "{i: 287454020, c: 15}") == 0); + free(str); + + eina_value_flush(&other); + + fail_unless(eina_value_struct_setup(&other, &mybigst_desc)); + fail_unless(eina_value_struct_set(&other, "a", 1) ); + fail_unless(eina_value_struct_set(&other, "b", 2)); + fail_unless(eina_value_struct_set(&other, "c", 3)); + fail_unless(eina_value_struct_set(&other, "d", 4)); + fail_unless(eina_value_struct_set(&other, "e", 5)); + fail_unless(eina_value_struct_set(&other, "f", 6)); + fail_unless(eina_value_struct_set(&other, "g", 7)); + fail_unless(eina_value_struct_set(&other, "h", 8)); + fail_unless(eina_value_struct_set(&other, "i", 9)); + fail_unless(eina_value_struct_set(&other, "j", 10)); + fail_unless(eina_value_struct_set(&other, "k", 12)); + fail_unless(eina_value_struct_set(&other, "l", 13)); + fail_unless(eina_value_struct_set(&other, "m", 14)); + fail_unless(eina_value_struct_set(&other, "n", 15)); + fail_unless(eina_value_struct_set(&other, "o", 16)); + fail_unless(eina_value_struct_set(&other, "p", 17)); + fail_unless(eina_value_struct_set(&other, "q", 18)); + fail_unless(eina_value_struct_set(&other, "r", 19)); + fail_unless(eina_value_struct_set(&other, "s", 20)); + fail_unless(eina_value_struct_set(&other, "t", 21)); + fail_unless(eina_value_struct_set(&other, "u", 22)); + fail_unless(eina_value_struct_set(&other, "v", 23)); + fail_unless(eina_value_struct_set(&other, "x", 24)); + + fail_unless(eina_value_struct_get(&other, "a", &i)); + fail_unless(i == 1); + fail_unless(eina_value_struct_get(&other, "b", &i)); + fail_unless(i == 2); + fail_unless(eina_value_struct_get(&other, "c", &i)); + fail_unless(i == 3); + fail_unless(eina_value_struct_get(&other, "d", &i)); + fail_unless(i == 4); + fail_unless(eina_value_struct_get(&other, "e", &i)); + fail_unless(i == 5); + fail_unless(eina_value_struct_get(&other, "f", &i)); + fail_unless(i == 6); + fail_unless(eina_value_struct_get(&other, "g", &i)); + fail_unless(i == 7); + fail_unless(eina_value_struct_get(&other, "h", &i)); + fail_unless(i == 8); + fail_unless(eina_value_struct_get(&other, "i", &i)); + fail_unless(i == 9); + fail_unless(eina_value_struct_get(&other, "j", &i)); + fail_unless(i == 10); + fail_unless(eina_value_struct_get(&other, "k", &i)); + fail_unless(i == 12); + fail_unless(eina_value_struct_get(&other, "l", &i)); + fail_unless(i == 13); + fail_unless(eina_value_struct_get(&other, "m", &i)); + fail_unless(i == 14); + fail_unless(eina_value_struct_get(&other, "n", &i)); + fail_unless(i == 15); + fail_unless(eina_value_struct_get(&other, "o", &i)); + fail_unless(i == 16); + fail_unless(eina_value_struct_get(&other, "p", &i)); + fail_unless(i == 17); + fail_unless(eina_value_struct_get(&other, "q", &i)); + fail_unless(i == 18); + fail_unless(eina_value_struct_get(&other, "r", &i)); + fail_unless(i == 19); + fail_unless(eina_value_struct_get(&other, "s", &i)); + fail_unless(i == 20); + fail_unless(eina_value_struct_get(&other, "t", &i)); + fail_unless(i == 21); + fail_unless(eina_value_struct_get(&other, "u", &i)); + fail_unless(i == 22); + fail_unless(eina_value_struct_get(&other, "v", &i)); + fail_unless(i == 23); + fail_unless(eina_value_struct_get(&other, "x", &i)); + fail_unless(i == 24); + + str = eina_value_to_string(&other); + fail_unless(str != NULL); + fail_unless(strcmp(str, "{a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8, i: 9, j: 10, k: 12, l: 13, m: 14, n: 15, o: 16, p: 17, q: 18, r: 19, s: 20, t: 21, u: 22, v: 23, x: 24}") == 0); + free(str); + + eina_value_free(value); + eina_shutdown(); +} +END_TEST + void eina_test_value(TCase *tc) { @@ -1554,4 +1728,5 @@ eina_test_value(TCase *tc) tcase_add_test(tc, eina_value_test_hash); tcase_add_test(tc, eina_value_test_timeval); tcase_add_test(tc, eina_value_test_blob); + tcase_add_test(tc, eina_value_test_struct); }