diff options
author | kpfleming <kpfleming@f38db490-d61c-443f-a65b-d21fe96a405b> | 2006-01-26 04:00:05 +0000 |
---|---|---|
committer | kpfleming <kpfleming@f38db490-d61c-443f-a65b-d21fe96a405b> | 2006-01-26 04:00:05 +0000 |
commit | de2fd6aebf2f638dc0947778ce087529295ad3d3 (patch) | |
tree | 0aa7c1312e44030aa06217b02912d3a26f1c106c /utils.c | |
parent | 0e2d8be747fbb9454768f26c60a5e6deb89ec059 (diff) |
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: http://svn.digium.com/svn/asterisk/trunk@8697 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'utils.c')
-rw-r--r-- | utils.c | 82 |
1 files changed, 49 insertions, 33 deletions
@@ -944,70 +944,86 @@ void ast_join(char *s, size_t len, char * const w[]) 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) { int index; - pool->base = calloc(1, size); - if (pool->base) { - pool->size = size; - pool->space = size; - for (index = 0; index < num_fields; index++) - fields[index] = __ast_string_field_empty; - } - return pool->base ? 0 : -1; + if (add_string_pool(mgr, size)) + return -1; + + for (index = 0; index < num_fields; index++) + fields[index] = __ast_string_field_empty; + + 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) { char *result = NULL; - if (__builtin_expect(needed > pool->space, 0)) { - int index; - char *new_base; - size_t new_size = pool->size * 2; + if (__builtin_expect(needed > mgr->space, 0)) { + size_t new_size = mgr->size * 2; - while (new_size < (pool->used + needed)) + while (new_size < needed) new_size *= 2; - if (!(new_base = realloc(pool->base, new_size))) + if (add_string_pool(mgr, new_size)) 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; - pool->used += needed; - pool->space -= needed; + result = mgr->pool->base + mgr->used; + mgr->used += needed; + mgr->space -= needed; 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, int index, const char *format, ...) { - char s; size_t needed; va_list ap1, ap2; va_start(ap1, format); 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); - if ((fields[index] = __ast_string_field_alloc_space(pool, needed, fields, num_fields))) - vsprintf((char *) fields[index], format, ap2); + if (needed > mgr->space) { + 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); } |