Add aggregate operations for stuctures with string fields

Add struct-level comparison and copying of string fields to reduce the
complexity of whole-struct comparison and copying when using string
fields. The new macros do not take into account non-stringfield data.

Review: https://reviewboard.asterisk.org/r/2308/


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@381017 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
Kinsey Moore 2013-02-07 15:16:44 +00:00
parent 345253a50e
commit 67102c3d3f
2 changed files with 181 additions and 7 deletions

View File

@ -311,11 +311,14 @@ void __ast_string_field_release_active(struct ast_string_field_pool *pool_head,
\param x Pointer to a structure containing fields
\param ptr Pointer to a field within the structure
\param data String value to be copied into the field
\return nothing
\retval zero on success
\retval non-zero on error
*/
#define ast_string_field_ptr_set(x, ptr, data) ast_string_field_ptr_set_by_fields((x)->__field_mgr_pool, (x)->__field_mgr, ptr, data)
#define ast_string_field_ptr_set_by_fields(field_mgr_pool, field_mgr, ptr, data) do { \
#define ast_string_field_ptr_set_by_fields(field_mgr_pool, field_mgr, ptr, data) \
({ \
int __res__ = 0; \
const char *__d__ = (data); \
size_t __dlen__ = (__d__) ? strlen(__d__) + 1 : 1; \
ast_string_field *__p__ = (ast_string_field *) (ptr); \
@ -329,19 +332,21 @@ void __ast_string_field_release_active(struct ast_string_field_pool *pool_head,
__ast_string_field_release_active(field_mgr_pool, (*ptr)); \
} \
memcpy(* (void **) __p__, __d__, __dlen__); \
} else { \
__res__ = -1; \
} \
} while (0)
__res__; \
})
/*!
\brief Set a field to a simple string value
\param x Pointer to a structure containing fields
\param field Name of the field to set
\param data String value to be copied into the field
\return nothing
\retval zero on success
\retval non-zero on error
*/
#define ast_string_field_set(x, field, data) do { \
ast_string_field_ptr_set(x, &(x)->field, data); \
} while (0)
#define ast_string_field_set(x, field, data) ast_string_field_ptr_set(x, &(x)->field, data)
/*!
\brief Set a field to a complex (built) value
@ -387,4 +392,65 @@ void __ast_string_field_release_active(struct ast_string_field_pool *pool_head,
#define ast_string_field_build_va(x, field, fmt, args) \
__ast_string_field_ptr_build_va(&(x)->__field_mgr, &(x)->__field_mgr_pool, (ast_string_field *) &(x)->field, fmt, args)
/*!
\brief Compare the string fields in two instances of the same structure
\since 12
\param instance1 The first instance of the structure to be compared
\param instance2 The second instance of the structure to be compared
\retval zero if all string fields are equal (does not compare non-string field data)
\retval non-zero if the values of the string fields differ
*/
#define ast_string_fields_cmp(instance1, instance2) \
({ \
int __res__ = 0; \
size_t __ptr_size__ = sizeof(char *); \
int __len__ = ((void *)&(instance1)->__field_mgr - (void *)&(instance1)->__field_mgr_pool)/__ptr_size__ - 1; \
int __len2__ = ((void *)&(instance2)->__field_mgr - (void *)&(instance2)->__field_mgr_pool)/__ptr_size__ - 1; \
if (__len__ == __len2__) { \
char **__head1__ = (void *)&(instance1)->__field_mgr_pool + __ptr_size__; \
char **__head2__ = (void *)&(instance2)->__field_mgr_pool + __ptr_size__; \
for (__len__ -= 1; __len__ >= 0; __len__--) { \
__res__ = strcmp(__head1__[__len__], __head2__[__len__]); \
if (__res__) { \
break; \
} \
} \
} else { \
__res__ = -1; \
} \
__res__; \
})
/*!
\brief Copy all string fields from one instance to another of the same structure
\since 12
\param copy The instance of the structure to be copied into
\param orig The instance of the structure to be copied from
\retval zero on success
\retval non-zero on error
*/
#define ast_string_fields_copy(copy, orig) \
({ \
int __outer_res__ = 0; \
size_t __ptr_size__ = sizeof(char *); \
int __len__ = ((void *)&(copy)->__field_mgr - (void *)&(copy)->__field_mgr_pool)/__ptr_size__ - 1; \
int __len2__ = ((void *)&(orig)->__field_mgr - (void *)&(orig)->__field_mgr_pool)/__ptr_size__ - 1; \
if (__len__ == __len2__) { \
char **__copy_head__ = (void *)&(copy)->__field_mgr_pool + __ptr_size__; \
char **__orig_head__ = (void *)&(orig)->__field_mgr_pool + __ptr_size__; \
for (__len2__ -= 1; __len2__ >= 0; __len2__--) { \
__ast_string_field_release_active((copy)->__field_mgr_pool, __copy_head__[__len2__]); \
} \
for (__len__ -= 1; __len__ >= 0; __len__--) { \
if (ast_string_field_ptr_set((copy), &__copy_head__[__len__], __orig_head__[__len__])) { \
__outer_res__ = -1; \
break; \
} \
} \
} else { \
__outer_res__ = -1; \
} \
__outer_res__; \
})
#endif /* _ASTERISK_STRINGFIELDS_H */

View File

@ -294,8 +294,115 @@ error:
return AST_TEST_FAIL;
}
AST_TEST_DEFINE(string_field_aggregate_test)
{
struct test_struct {
AST_DECLARE_STRING_FIELDS (
AST_STRING_FIELD(string1);
AST_STRING_FIELD(string2);
);
int foo;
} inst1, inst2, inst3, inst4;
switch (cmd) {
case TEST_INIT:
info->name = "string_field_aggregate_test";
info->category = "/main/utils/";
info->summary = "Test stringfield aggregate operations";
info->description =
"This tests the structure comparison and copy macros of the stringfield API";
return AST_TEST_NOT_RUN;
case TEST_EXECUTE:
break;
}
ast_string_field_init(&inst1, 32);
ast_string_field_init(&inst2, 32);
ast_string_field_init(&inst3, 32);
ast_string_field_init(&inst4, 32);
ast_string_field_set(&inst1, string1, "foo");
ast_string_field_set(&inst1, string2, "bar");
inst1.foo = 1;
ast_string_field_set(&inst2, string2, "bar");
ast_string_field_set(&inst2, string1, "foo");
inst2.foo = 2;
ast_string_field_set(&inst3, string1, "foo");
ast_string_field_set(&inst3, string2, "baz");
inst3.foo = 3;
ast_string_field_set(&inst4, string1, "faz");
ast_string_field_set(&inst4, string2, "baz");
inst4.foo = 3;
if (ast_string_fields_cmp(&inst1, &inst2)) {
ast_test_status_update(test, "Structures 1/2 should be equal!\n");
goto error;
} else {
ast_test_status_update(test, "Structures 1/2 are equal as expected.\n");
}
if (!ast_string_fields_cmp(&inst1, &inst3)) {
ast_test_status_update(test, "Structures 1/3 should be different!\n");
goto error;
} else {
ast_test_status_update(test, "Structures 1/3 are different as expected.\n");
}
if (!ast_string_fields_cmp(&inst2, &inst3)) {
ast_test_status_update(test, "Structures 2/3 should be different!\n");
goto error;
} else {
ast_test_status_update(test, "Structures 2/3 are different as expected.\n");
}
if (!ast_string_fields_cmp(&inst3, &inst4)) {
ast_test_status_update(test, "Structures 3/4 should be different!\n");
goto error;
} else {
ast_test_status_update(test, "Structures 3/4 are different as expected.\n");
}
if (ast_string_fields_copy(&inst1, &inst3)) {
ast_test_status_update(test, "Copying from structure 3 to structure 4 failed!\n");
goto error;
} else {
ast_test_status_update(test, "Copying from structure 3 to structure 4 succeeded!\n");
}
/* inst1 and inst3 should now be equal and inst1 should no longer be equal to inst2 */
if (ast_string_fields_cmp(&inst1, &inst3)) {
ast_test_status_update(test, "Structures 1/3 should be equal!\n");
goto error;
} else {
ast_test_status_update(test, "Structures 1/3 are equal as expected.\n");
}
if (!ast_string_fields_cmp(&inst1, &inst2)) {
ast_test_status_update(test, "Structures 1/2 should be different!\n");
goto error;
} else {
ast_test_status_update(test, "Structures 1/2 are different as expected.\n");
}
ast_string_field_free_memory(&inst1);
ast_string_field_free_memory(&inst2);
ast_string_field_free_memory(&inst3);
ast_string_field_free_memory(&inst4);
return AST_TEST_PASS;
error:
ast_string_field_free_memory(&inst1);
ast_string_field_free_memory(&inst2);
ast_string_field_free_memory(&inst3);
ast_string_field_free_memory(&inst4);
return AST_TEST_FAIL;
}
static int unload_module(void)
{
AST_TEST_UNREGISTER(string_field_aggregate_test);
AST_TEST_UNREGISTER(string_field_test);
return 0;
}
@ -303,6 +410,7 @@ static int unload_module(void)
static int load_module(void)
{
AST_TEST_REGISTER(string_field_test);
AST_TEST_REGISTER(string_field_aggregate_test);
return AST_MODULE_LOAD_SUCCESS;
}