string field manager improvements:
authorKevin P. Fleming <kpfleming@digium.com>
Thu, 26 Jan 2006 04:00:05 +0000 (04:00 +0000)
committerKevin P. Fleming <kpfleming@digium.com>
Thu, 26 Jan 2006 04:00:05 +0000 (04:00 +0000)
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

include/asterisk/stringfields.h
utils.c

index 5631682..22e066d 100644 (file)
@@ -107,31 +107,40 @@ extern const char *__ast_string_field_empty;
 
 /*!
   \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 {
-       char *base;     /*!< the address of the pool's base in memory */
-       size_t size;    /*!< the total size of the pool */
-       size_t space;   /*!< the space available in the pool */
-       size_t used;    /*!< the space used in the pool */
+       struct ast_string_field_pool *prev;     /*!< pointer to the previous pool, if any */
+       char base[0];                           /*!< storage space for the fields */
 };
 
 /*!
   \internal
-  \brief Initialize a field pool and fields
-  \param pool Pointer to the pool structure
+  \brief Structure used to manage the storage for a set of string fields
+*/
+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 fields Pointer to the first entry of the field array
   \param num_fields Number of fields in the array
   \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);
 
 /*!
   \internal
-  \brief Allocate space for field in the pool
-  \param pool Pointer to the pool structure
+  \brief Allocate space for a field
+  \param mgr Pointer to the pool manager structure
   \param needed Amount of space needed for this field
   \param fields Pointer to the first entry of the field 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
   the field pool. If the requested amount of space is not available,
-  the pool will be expanded until enough space becomes available,
-  and the existing fields stored there will be updated to point
-  into the new pool.
+  an additional pool will be allocated.
 */
-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);
 
 /*!
   \internal
   \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 num_fields Number of fields in the array
   \param index Index position of the field within the structure
   \param format printf-style format string
   \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,
                                    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]; \
        field_list \
        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
@@ -205,7 +212,7 @@ void __ast_string_field_index_build(struct ast_string_field_pool *pool,
   \return 0 on failure, non-zero on success
 */
 #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
@@ -215,7 +222,7 @@ void __ast_string_field_index_build(struct ast_string_field_pool *pool,
   \return nothing
 */
 #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); \
        } while (0)
 
@@ -238,7 +245,7 @@ void __ast_string_field_index_build(struct ast_string_field_pool *pool,
   \return nothing
 */
 #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
@@ -289,9 +296,13 @@ void __ast_string_field_index_build(struct ast_string_field_pool *pool,
 */
 #define ast_string_field_free_all(x) do { \
        int index; \
+       struct ast_string_field_pool *this, *prev; \
        for (index = 0; index < ast_string_field_count(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)
 
 #endif /* _ASTERISK_STRINGFIELDS_H */
diff --git a/utils.c b/utils.c
index ef02462..977f0cd 100644 (file)
--- a/utils.c
+++ b/utils.c
@@ -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);
 }