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.



SVN revision: 67155
This commit is contained in:
Gustavo Sverzut Barbieri 2012-01-12 22:58:31 +00:00
parent 32392d38f8
commit b1feb2fe8c
4 changed files with 1393 additions and 20 deletions

View File

@ -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)

View File

@ -301,6 +301,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);
@ -2414,6 +2460,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.

View File

@ -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;
}

View File

@ -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);
}