summaryrefslogtreecommitdiff
path: root/include/asterisk/stringfields.h
diff options
context:
space:
mode:
authorKevin P. Fleming <kpfleming@digium.com>2009-03-31 21:29:50 +0000
committerKevin P. Fleming <kpfleming@digium.com>2009-03-31 21:29:50 +0000
commita009068110039a455bdc916a57d8cd0d0f700da1 (patch)
treeab85731f88b1c616beae92181e46f305c38adad2 /include/asterisk/stringfields.h
parentd18a0cecdfdb2fae117d768210729254aeb61150 (diff)
Optimizations to the stringfields API
This patch provides a number of optimizations to the stringfields API, focused around saving (not wasting) memory whenever possible. Thanks to Mark Michelson for inspiring this work and coming up with the first two optimizations that are represented here: Changes: - Cleanup of some code, fix incorrect doxygen comments - When a field is emptied or replaced with a new allocation, decrease the amount of 'active' space in the pool it was held in; if that pool reaches zero active space, and is not the current pool, then free it as it is no longer in use - When allocating a pool, try to allocate a size that will fit in a 'standard' malloc() allocation without wasting space - When allocating space for a field, store the amount of space in the two bytes immediately preceding the field; this eliminates the need to call strlen() on the field when overwriting it, and more importantly it 'remembers' the amount of space the field has available, even if a shorter string has been stored in it since it was allocated - Don't automatically double the size of each successive pool allocated; it's wasteful http://reviewboard.digium.com/r/165/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@185581 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'include/asterisk/stringfields.h')
-rw-r--r--include/asterisk/stringfields.h89
1 files changed, 58 insertions, 31 deletions
diff --git a/include/asterisk/stringfields.h b/include/asterisk/stringfields.h
index 9c48bfda2..2b9b7b230 100644
--- a/include/asterisk/stringfields.h
+++ b/include/asterisk/stringfields.h
@@ -57,25 +57,23 @@
Fields will default to pointing to an empty string, and will revert to
that when ast_string_field_set() is called with a NULL argument.
- A string field will \b never contain NULL (this feature is not used
- in this code, but comes from external requirements).
+ A string field will \b never contain NULL.
ast_string_field_init(x, 0) will reset fields to the
initial value while keeping the pool allocated.
Reading the fields is much like using 'const char * const' fields in the
- structure: you cannot write to the field or to the memory it points to
- (XXX perhaps the latter is too much of a restriction since values
- are not shared).
+ structure: you cannot write to the field or to the memory it points to.
Writing to the fields must be done using the wrapper macros listed below;
and assignments are always by value (i.e. strings are copied):
* ast_string_field_set() stores a simple value;
- * ast_string_field_build() builds the string using a printf-style;
+ * ast_string_field_build() builds the string using a printf-style format;
* ast_string_field_build_va() is the varargs version of the above (for
- portability reasons it uses two vararg);
+ portability reasons it uses two vararg arguments);
* variants of these function allow passing a pointer to the field
as an argument.
+
\code
ast_string_field_set(x, foo, "infinite loop");
ast_string_field_set(x, foo, NULL); // set to an empty string
@@ -110,6 +108,9 @@
Don't declare instances of this type directly; use the AST_STRING_FIELD()
macro instead.
+
+ In addition to the string itself, the amount of space allocated for the
+ field is stored in the two bytes immediately preceding it.
*/
typedef const char * ast_string_field;
@@ -117,7 +118,7 @@ typedef const char * ast_string_field;
\internal
\brief A constant empty string used for fields that have no other value
*/
-extern const char __ast_string_field_empty[];
+extern const char *__ast_string_field_empty;
/*!
\internal
@@ -125,18 +126,17 @@ extern const char __ast_string_field_empty[];
*/
struct ast_string_field_pool {
struct ast_string_field_pool *prev; /*!< pointer to the previous pool, if any */
+ size_t size; /*!< the total size of the pool */
+ size_t used; /*!< the space used in the pool */
+ size_t active; /*!< the amount of space actively in use by fields */
char base[0]; /*!< storage space for the fields */
};
/*!
\internal
\brief Structure used to manage the storage for a set of string fields.
- Because of the way pools are managed, we can only allocate from the topmost
- pool, so the numbers here reflect just that.
*/
struct ast_string_field_mgr {
- size_t size; /*!< the total size of the current pool */
- size_t used; /*!< the space used in the current pool */
ast_string_field last_alloc; /*!< the last field allocated */
};
@@ -154,7 +154,8 @@ struct ast_string_field_mgr {
the pool has enough space available. If so, the additional space will be
allocated to this field and the field's address will not be changed.
*/
-int __ast_string_field_ptr_grow(struct ast_string_field_mgr *mgr, size_t needed,
+int __ast_string_field_ptr_grow(struct ast_string_field_mgr *mgr,
+ struct ast_string_field_pool **pool_head, size_t needed,
const ast_string_field *ptr);
/*!
@@ -176,7 +177,7 @@ ast_string_field __ast_string_field_alloc_space(struct ast_string_field_mgr *mgr
\internal
\brief Set a field to a complex (built) value
\param mgr Pointer to the pool manager structure
- \param fields Pointer to the first entry of the field array
+ \param pool_head Pointer to the current pool
\param ptr Pointer to a field within the structure
\param format printf-style format string
\return nothing
@@ -189,7 +190,7 @@ void __ast_string_field_ptr_build(struct ast_string_field_mgr *mgr,
\internal
\brief Set a field to a complex (built) value
\param mgr Pointer to the pool manager structure
- \param fields Pointer to the first entry of the field array
+ \param pool_head Pointer to the current pool
\param ptr Pointer to a field within the structure
\param format printf-style format string
\param args va_list of the args for the format_string
@@ -242,29 +243,55 @@ void __ast_string_field_ptr_build_va(struct ast_string_field_mgr *mgr,
/*! \internal \brief internal version of ast_string_field_init */
int __ast_string_field_init(struct ast_string_field_mgr *mgr,
- struct ast_string_field_pool **pool_head, int needed);
+ struct ast_string_field_pool **pool_head, int needed);
+
+/*!
+ \internal
+ \brief Release a field's allocation from a pool
+ \param pool_head Pointer to the current pool
+ \param ptr Field to be released
+ \return nothing
+
+ This function will search the pool list to find the pool that contains
+ the allocation for the specified field, then remove the field's allocation
+ from that pool's 'active' count. If the pool's active count reaches zero,
+ and it is not the current pool, then it will be freed.
+ */
+void __ast_string_field_release_active(struct ast_string_field_pool *pool_head,
+ const ast_string_field ptr);
+
+/* the type of storage used to track how many bytes were allocated for a field */
+
+typedef uint16_t ast_string_field_allocation;
+
+/*!
+ \brief Macro to provide access to the allocation field that lives immediately in front of a string field
+ \param x Pointer to the string field
+*/
+#define AST_STRING_FIELD_ALLOCATION(x) *((ast_string_field_allocation *) (x - sizeof(ast_string_field_allocation)))
/*!
\brief Set a field to a simple string value
\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
+ \param data String value to be copied into the field
\return nothing
*/
-#define ast_string_field_ptr_set(x, ptr, data) do { \
- const char *__d__ = (data); \
- size_t __dlen__ = (__d__) ? strlen(__d__) + 1 : 1; \
- const char **__p__ = (const char **) (ptr); \
- char *__q__; \
- if (__dlen__ == 1) \
- *__p__ = __ast_string_field_empty; \
- else if (!__ast_string_field_ptr_grow(&(x)->__field_mgr, __dlen__, ptr)) { \
- __q__ = (char *) *__p__; \
- memcpy(__q__, __d__, __dlen__); \
- } else if ((*__p__ = __ast_string_field_alloc_space(&(x)->__field_mgr, &(x)->__field_mgr_pool, __dlen__))) { \
- __q__ = (char *) *__p__; \
- memcpy(__q__, __d__, __dlen__); \
- } \
+#define ast_string_field_ptr_set(x, ptr, data) do { \
+ const char *__d__ = (data); \
+ size_t __dlen__ = (__d__) ? strlen(__d__) + 1 : 1; \
+ ast_string_field *__p__ = (ast_string_field *) (ptr); \
+ if (__dlen__ == 1) { \
+ __ast_string_field_release_active((x)->__field_mgr_pool, *__p__); \
+ *__p__ = __ast_string_field_empty; \
+ } else if ((__dlen__ <= AST_STRING_FIELD_ALLOCATION(*__p__)) || \
+ (!__ast_string_field_ptr_grow(&(x)->__field_mgr, &(x)->__field_mgr_pool, __dlen__, __p__)) || \
+ (*__p__ = __ast_string_field_alloc_space(&(x)->__field_mgr, &(x)->__field_mgr_pool, __dlen__))) { \
+ if (*__p__ != (*ptr)) { \
+ __ast_string_field_release_active((x)->__field_mgr_pool, (*ptr)); \
+ } \
+ memcpy((void *) *__p__, __d__, __dlen__); \
+ } \
} while (0)
/*!