string field manager improvements:

use multiple memory blocks, instead of realloc(), ensuring that field pointers will never become invalid or change
don't run vs(n)printf twice when doing a field build unless required


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@8697 65c4cc65-6c06-0410-ace0-fbb531ad65f3
1.4
Kevin P. Fleming 20 years ago
parent 99872975bf
commit 4467ab62c8

@ -107,31 +107,40 @@ extern const char *__ast_string_field_empty;
/*! /*!
\internal \internal
\brief Structure used to manage the storage for a field pool \brief Structure used to hold a pool of space for string fields
*/ */
struct ast_string_field_pool { struct ast_string_field_pool {
char *base; /*!< the address of the pool's base in memory */ struct ast_string_field_pool *prev; /*!< pointer to the previous pool, if any */
size_t size; /*!< the total size of the pool */ char base[0]; /*!< storage space for the fields */
size_t space; /*!< the space available in the pool */
size_t used; /*!< the space used in the pool */
}; };
/*! /*!
\internal \internal
\brief Initialize a field pool and fields \brief Structure used to manage the storage for a set of string fields
\param pool Pointer to the pool structure */
struct ast_string_field_mgr {
struct ast_string_field_pool *pool; /*!< the address of the pool's structure */
size_t size; /*!< the total size of the current pool */
size_t space; /*!< the space available in the current pool */
size_t used; /*!< the space used in the current pool */
};
/*!
\internal
\brief Initialize a field pool manager and fields
\param mgr Pointer to the pool manager structure
\param size Amount of storage to allocate \param size Amount of storage to allocate
\param fields Pointer to the first entry of the field array \param fields Pointer to the first entry of the field array
\param num_fields Number of fields in the array \param num_fields Number of fields in the array
\return 0 on failure, non-zero on success \return 0 on failure, non-zero on success
*/ */
int __ast_string_field_init(struct ast_string_field_pool *pool, size_t size, int __ast_string_field_init(struct ast_string_field_mgr *mgr, size_t size,
ast_string_field *fields, int num_fields); ast_string_field *fields, int num_fields);
/*! /*!
\internal \internal
\brief Allocate space for field in the pool \brief Allocate space for a field
\param pool Pointer to the pool structure \param mgr Pointer to the pool manager structure
\param needed Amount of space needed for this field \param needed Amount of space needed for this field
\param fields Pointer to the first entry of the field array \param fields Pointer to the first entry of the field array
\param num_fields Number of fields in the array \param num_fields Number of fields in the array
@ -139,24 +148,22 @@ int __ast_string_field_init(struct ast_string_field_pool *pool, size_t size,
This function will allocate the requested amount of space from This function will allocate the requested amount of space from
the field pool. If the requested amount of space is not available, the field pool. If the requested amount of space is not available,
the pool will be expanded until enough space becomes available, an additional pool will be allocated.
and the existing fields stored there will be updated to point
into the new pool.
*/ */
ast_string_field __ast_string_field_alloc_space(struct ast_string_field_pool *pool, size_t needed, ast_string_field __ast_string_field_alloc_space(struct ast_string_field_mgr *mgr, size_t needed,
ast_string_field *fields, int num_fields); ast_string_field *fields, int num_fields);
/*! /*!
\internal \internal
\brief Set a field to a complex (built) value \brief Set a field to a complex (built) value
\param pool Pointer to the pool structure \param mgr Pointer to the pool manager structure
\param fields Pointer to the first entry of the field array \param fields Pointer to the first entry of the field array
\param num_fields Number of fields in the array \param num_fields Number of fields in the array
\param index Index position of the field within the structure \param index Index position of the field within the structure
\param format printf-style format string \param format printf-style format string
\return nothing \return nothing
*/ */
void __ast_string_field_index_build(struct ast_string_field_pool *pool, void __ast_string_field_index_build(struct ast_string_field_mgr *mgr,
ast_string_field *fields, int num_fields, ast_string_field *fields, int num_fields,
int index, const char *format, ...); int index, const char *format, ...);
@ -179,7 +186,7 @@ void __ast_string_field_index_build(struct ast_string_field_pool *pool,
ast_string_field __begin_field[0]; \ ast_string_field __begin_field[0]; \
field_list \ field_list \
ast_string_field __end_field[0]; \ ast_string_field __end_field[0]; \
struct ast_string_field_pool __field_pool; struct ast_string_field_mgr __field_mgr;
/*! /*!
\brief Get the number of string fields in a structure \brief Get the number of string fields in a structure
@ -205,7 +212,7 @@ void __ast_string_field_index_build(struct ast_string_field_pool *pool,
\return 0 on failure, non-zero on success \return 0 on failure, non-zero on success
*/ */
#define ast_string_field_init(x) \ #define ast_string_field_init(x) \
__ast_string_field_init(&x->__field_pool, AST_STRING_FIELD_DEFAULT_POOL, &x->__begin_field[0], ast_string_field_count(x)) __ast_string_field_init(&x->__field_mgr, AST_STRING_FIELD_DEFAULT_POOL, &x->__begin_field[0], ast_string_field_count(x))
/*! /*!
\brief Set a field to a simple string value \brief Set a field to a simple string value
@ -215,7 +222,7 @@ void __ast_string_field_index_build(struct ast_string_field_pool *pool,
\return nothing \return nothing
*/ */
#define ast_string_field_index_set(x, index, data) do { \ #define ast_string_field_index_set(x, index, data) do { \
if ((x->__begin_field[index] = __ast_string_field_alloc_space(&x->__field_pool, strlen(data) + 1, &x->__begin_field[0], ast_string_field_count(x)))) \ if ((x->__begin_field[index] = __ast_string_field_alloc_space(&x->__field_mgr, strlen(data) + 1, &x->__begin_field[0], ast_string_field_count(x)))) \
strcpy((char *) x->__begin_field[index], data); \ strcpy((char *) x->__begin_field[index], data); \
} while (0) } while (0)
@ -238,7 +245,7 @@ void __ast_string_field_index_build(struct ast_string_field_pool *pool,
\return nothing \return nothing
*/ */
#define ast_string_field_index_build(x, index, fmt, args...) \ #define ast_string_field_index_build(x, index, fmt, args...) \
__ast_string_field_index_build(&x->__field_pool, &x->__begin_field[0], ast_string_field_count(x), index, fmt, args) __ast_string_field_index_build(&x->__field_mgr, &x->__begin_field[0], ast_string_field_count(x), index, fmt, args)
/*! /*!
\brief Set a field to a complex (built) value \brief Set a field to a complex (built) value
@ -289,9 +296,13 @@ void __ast_string_field_index_build(struct ast_string_field_pool *pool,
*/ */
#define ast_string_field_free_all(x) do { \ #define ast_string_field_free_all(x) do { \
int index; \ int index; \
struct ast_string_field_pool *this, *prev; \
for (index = 0; index < ast_string_field_count(x); index ++) \ for (index = 0; index < ast_string_field_count(x); index ++) \
ast_string_field_index_free(x, index); \ ast_string_field_index_free(x, index); \
free(x->__field_pool.base); \ for (this = x->__field_mgr.pool; this; this = prev) { \
prev = this->prev; \
free(this); \
} \
} while(0) } while(0)
#endif /* _ASTERISK_STRINGFIELDS_H */ #endif /* _ASTERISK_STRINGFIELDS_H */

@ -944,70 +944,86 @@ void ast_join(char *s, size_t len, char * const w[])
const char const *__ast_string_field_empty = ""; const char const *__ast_string_field_empty = "";
int __ast_string_field_init(struct ast_string_field_pool *pool, size_t size, static int add_string_pool(struct ast_string_field_mgr *mgr, size_t size)
{
struct ast_string_field_pool *pool;
if (!(pool = ast_calloc(1, sizeof(*pool) + size)))
return -1;
pool->prev = mgr->pool;
mgr->pool = pool;
mgr->size = size;
mgr->space = size;
mgr->used = 0;
return 0;
}
int __ast_string_field_init(struct ast_string_field_mgr *mgr, size_t size,
ast_string_field *fields, int num_fields) ast_string_field *fields, int num_fields)
{ {
int index; int index;
pool->base = calloc(1, size); if (add_string_pool(mgr, size))
if (pool->base) { return -1;
pool->size = size;
pool->space = size;
for (index = 0; index < num_fields; index++) for (index = 0; index < num_fields; index++)
fields[index] = __ast_string_field_empty; fields[index] = __ast_string_field_empty;
}
return pool->base ? 0 : -1; return 0;
} }
ast_string_field __ast_string_field_alloc_space(struct ast_string_field_pool *pool, size_t needed, ast_string_field __ast_string_field_alloc_space(struct ast_string_field_mgr *mgr, size_t needed,
ast_string_field *fields, int num_fields) ast_string_field *fields, int num_fields)
{ {
char *result = NULL; char *result = NULL;
if (__builtin_expect(needed > pool->space, 0)) { if (__builtin_expect(needed > mgr->space, 0)) {
int index; size_t new_size = mgr->size * 2;
char *new_base;
size_t new_size = pool->size * 2;
while (new_size < (pool->used + needed)) while (new_size < needed)
new_size *= 2; new_size *= 2;
if (!(new_base = realloc(pool->base, new_size))) if (add_string_pool(mgr, new_size))
return NULL; return NULL;
for (index = 0; index < num_fields; index++) {
if (fields[index] != __ast_string_field_empty)
fields[index] = new_base + (fields[index] - pool->base);
}
pool->base = new_base;
pool->space += new_size - pool->size;
pool->size = new_size;
} }
result = pool->base + pool->used; result = mgr->pool->base + mgr->used;
pool->used += needed; mgr->used += needed;
pool->space -= needed; mgr->space -= needed;
return result; return result;
} }
void __ast_string_field_index_build(struct ast_string_field_pool *pool, void __ast_string_field_index_build(struct ast_string_field_mgr *mgr,
ast_string_field *fields, int num_fields, ast_string_field *fields, int num_fields,
int index, const char *format, ...) int index, const char *format, ...)
{ {
char s;
size_t needed; size_t needed;
va_list ap1, ap2; va_list ap1, ap2;
va_start(ap1, format); va_start(ap1, format);
va_copy(ap2, ap1); va_copy(ap2, ap1);
needed = vsnprintf(&s, 1, format, ap1) + 1; needed = vsnprintf(mgr->pool->base + mgr->used, mgr->space, format, ap1) + 1;
va_end(ap1); va_end(ap1);
if ((fields[index] = __ast_string_field_alloc_space(pool, needed, fields, num_fields))) if (needed > mgr->space) {
vsprintf((char *) fields[index], format, ap2); size_t new_size = mgr->size * 2;
while (new_size < needed)
new_size *= 2;
if (add_string_pool(mgr, new_size))
return;
vsprintf(mgr->pool->base + mgr->used, format, ap2);
}
fields[index] = mgr->pool->base + mgr->used;
mgr->used += needed;
mgr->space -= needed;
va_end(ap2); va_end(ap2);
} }

Loading…
Cancel
Save