Optimizations to the stringfields API
[asterisk/asterisk.git] / include / asterisk / stringfields.h
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2006, Digium, Inc.
5  *
6  * Kevin P. Fleming <kpfleming@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20   \brief String fields in structures
21
22   This file contains objects and macros used to manage string
23   fields in structures without requiring them to be allocated
24   as fixed-size buffers or requiring individual allocations for
25   for each field.
26
27   Using this functionality is quite simple. An example structure
28   with three fields is defined like this:
29   
30   \code
31   struct sample_fields {
32           int x1;
33           AST_DECLARE_STRING_FIELDS(
34                   AST_STRING_FIELD(foo);
35                   AST_STRING_FIELD(bar);
36                   AST_STRING_FIELD(blah);
37           );
38           long x2;
39   };
40   \endcode
41   
42   When an instance of this structure is allocated (either statically or
43   dynamically), the fields and the pool of storage for them must be
44   initialized:
45   
46   \code
47   struct sample_fields *x;
48   
49   x = ast_calloc(1, sizeof(*x));
50   if (x == NULL || ast_string_field_init(x, 252)) {
51         if (x)
52                 ast_free(x);
53         x = NULL;
54         ... handle error
55   }
56   \endcode
57
58   Fields will default to pointing to an empty string, and will revert to
59   that when ast_string_field_set() is called with a NULL argument.
60   A string field will \b never contain NULL.
61
62   ast_string_field_init(x, 0) will reset fields to the
63   initial value while keeping the pool allocated.
64   
65   Reading the fields is much like using 'const char * const' fields in the
66   structure: you cannot write to the field or to the memory it points to.
67
68   Writing to the fields must be done using the wrapper macros listed below;
69   and assignments are always by value (i.e. strings are copied):
70   * ast_string_field_set() stores a simple value;
71   * ast_string_field_build() builds the string using a printf-style format;
72   * ast_string_field_build_va() is the varargs version of the above (for
73     portability reasons it uses two vararg arguments);
74   * variants of these function allow passing a pointer to the field
75     as an argument.
76
77   \code
78   ast_string_field_set(x, foo, "infinite loop");
79   ast_string_field_set(x, foo, NULL); // set to an empty string
80   ast_string_field_ptr_set(x, &x->bar, "right way");
81
82   ast_string_field_build(x, blah, "%d %s", zipcode, city);
83   ast_string_field_ptr_build(x, &x->blah, "%d %s", zipcode, city);
84
85   ast_string_field_build_va(x, bar, fmt, args1, args2)
86   ast_string_field_ptr_build_va(x, &x->bar, fmt, args1, args2)
87   \endcode
88
89   When the structure instance is no longer needed, the fields
90   and their storage pool must be freed:
91   
92   \code
93   ast_string_field_free_memory(x);
94   ast_free(x);
95   \endcode
96
97   This completes the API description.
98 */
99
100 #ifndef _ASTERISK_STRINGFIELDS_H
101 #define _ASTERISK_STRINGFIELDS_H
102
103 #include "asterisk/inline_api.h"
104
105 /*!
106   \internal
107   \brief An opaque type for managed string fields in structures
108
109   Don't declare instances of this type directly; use the AST_STRING_FIELD()
110   macro instead.
111
112   In addition to the string itself, the amount of space allocated for the
113   field is stored in the two bytes immediately preceding it.
114 */
115 typedef const char * ast_string_field;
116
117 /*!
118   \internal
119   \brief A constant empty string used for fields that have no other value
120 */
121 extern const char *__ast_string_field_empty;
122
123 /*!
124   \internal
125   \brief Structure used to hold a pool of space for string fields
126 */
127 struct ast_string_field_pool {
128         struct ast_string_field_pool *prev;     /*!< pointer to the previous pool, if any */
129         size_t size;                            /*!< the total size of the pool */
130         size_t used;                            /*!< the space used in the pool */
131         size_t active;                          /*!< the amount of space actively in use by fields */
132         char base[0];                           /*!< storage space for the fields */
133 };
134
135 /*!
136   \internal
137   \brief Structure used to manage the storage for a set of string fields.
138 */
139 struct ast_string_field_mgr {
140         ast_string_field last_alloc;            /*!< the last field allocated */
141 };
142
143 /*!
144   \internal
145   \brief Attempt to 'grow' an already allocated field to a larger size
146   \param mgr Pointer to the pool manager structure
147   \param needed Amount of space needed for this field
148   \param ptr Pointer to a field within the structure
149   \return 0 on success, non-zero on failure
150
151   This function will attempt to increase the amount of space allocated to
152   an existing field to the amount requested; this is only possible if the
153   field was the last field allocated from the current storage pool and
154   the pool has enough space available. If so, the additional space will be
155   allocated to this field and the field's address will not be changed.
156 */
157 int __ast_string_field_ptr_grow(struct ast_string_field_mgr *mgr,
158                                 struct ast_string_field_pool **pool_head, size_t needed,
159                                 const ast_string_field *ptr);
160
161 /*!
162   \internal
163   \brief Allocate space for a field
164   \param mgr Pointer to the pool manager structure
165   \param needed Amount of space needed for this field
166   \param fields Pointer to the first entry of the field array
167   \return NULL on failure, an address for the field on success.
168
169   This function will allocate the requested amount of space from
170   the field pool. If the requested amount of space is not available,
171   an additional pool will be allocated.
172 */
173 ast_string_field __ast_string_field_alloc_space(struct ast_string_field_mgr *mgr,
174                                                 struct ast_string_field_pool **pool_head, size_t needed);
175
176 /*!
177   \internal
178   \brief Set a field to a complex (built) value
179   \param mgr Pointer to the pool manager structure
180   \param pool_head Pointer to the current pool
181   \param ptr Pointer to a field within the structure
182   \param format printf-style format string
183   \return nothing
184 */
185 void __ast_string_field_ptr_build(struct ast_string_field_mgr *mgr,
186                                   struct ast_string_field_pool **pool_head,
187                                   ast_string_field *ptr, const char *format, ...) __attribute__((format(printf, 4, 5)));
188
189 /*!
190   \internal
191   \brief Set a field to a complex (built) value
192   \param mgr Pointer to the pool manager structure
193   \param pool_head Pointer to the current pool
194   \param ptr Pointer to a field within the structure
195   \param format printf-style format string
196   \param args va_list of the args for the format_string
197   \param args_again a copy of the first va_list for the sake of bsd not having a copy routine
198   \return nothing
199 */
200 void __ast_string_field_ptr_build_va(struct ast_string_field_mgr *mgr,
201                                      struct ast_string_field_pool **pool_head,
202                                      ast_string_field *ptr, const char *format, va_list a1, va_list a2) __attribute__((format(printf, 4, 0)));
203
204 /*!
205   \brief Declare a string field
206   \param name The field name
207 */
208 #define AST_STRING_FIELD(name) const ast_string_field name
209
210 /*!
211   \brief Declare the fields needed in a structure
212   \param field_list The list of fields to declare, using AST_STRING_FIELD() for each one.
213   Internally, string fields are stored as a pointer to the head of the pool,
214   followed by individual string fields, and then a struct ast_string_field_mgr
215   which describes the space allocated.
216   We split the two variables so they can be used as markers around the
217   field_list, and this allows us to determine how many entries are in
218   the field, and play with them.
219   In particular, for writing to the fields, we rely on __field_mgr_pool to be
220   a non-const pointer, so we know it has the same size as ast_string_field,
221   and we can use it to locate the fields.
222 */
223 #define AST_DECLARE_STRING_FIELDS(field_list) \
224         struct ast_string_field_pool *__field_mgr_pool; \
225         field_list                                      \
226         struct ast_string_field_mgr __field_mgr
227
228 /*!
229   \brief Initialize a field pool and fields
230   \param x Pointer to a structure containing fields
231   \param size Amount of storage to allocate.
232         Use 0 to reset fields to the default value,
233         and release all but the most recent pool.
234         size<0 (used internally) means free all pools.
235   \return 0 on success, non-zero on failure
236 */
237 #define ast_string_field_init(x, size) \
238         __ast_string_field_init(&(x)->__field_mgr, &(x)->__field_mgr_pool, size)
239
240 /*! \brief free all memory - to be called before destroying the object */
241 #define ast_string_field_free_memory(x) \
242         __ast_string_field_init(&(x)->__field_mgr, &(x)->__field_mgr_pool, -1)
243
244 /*! \internal \brief internal version of ast_string_field_init */
245 int __ast_string_field_init(struct ast_string_field_mgr *mgr,
246                             struct ast_string_field_pool **pool_head, int needed);
247
248 /*!
249   \internal
250   \brief Release a field's allocation from a pool
251   \param pool_head Pointer to the current pool
252   \param ptr Field to be released
253   \return nothing
254
255   This function will search the pool list to find the pool that contains
256   the allocation for the specified field, then remove the field's allocation
257   from that pool's 'active' count. If the pool's active count reaches zero,
258   and it is not the current pool, then it will be freed.
259  */
260 void __ast_string_field_release_active(struct ast_string_field_pool *pool_head,
261                                        const ast_string_field ptr);
262
263 /* the type of storage used to track how many bytes were allocated for a field */
264
265 typedef uint16_t ast_string_field_allocation;
266
267 /*!
268   \brief Macro to provide access to the allocation field that lives immediately in front of a string field
269   \param x Pointer to the string field
270 */
271 #define AST_STRING_FIELD_ALLOCATION(x) *((ast_string_field_allocation *) (x - sizeof(ast_string_field_allocation)))
272
273 /*!
274   \brief Set a field to a simple string value
275   \param x Pointer to a structure containing fields
276   \param ptr Pointer to a field within the structure
277   \param data String value to be copied into the field 
278   \return nothing
279 */
280 #define ast_string_field_ptr_set(x, ptr, data) do {                                                                     \
281         const char *__d__ = (data);                                                                                     \
282         size_t __dlen__ = (__d__) ? strlen(__d__) + 1 : 1;                                                              \
283         ast_string_field *__p__ = (ast_string_field *) (ptr);                                                           \
284         if (__dlen__ == 1) {                                                                                            \
285                 __ast_string_field_release_active((x)->__field_mgr_pool, *__p__);                                       \
286                 *__p__ = __ast_string_field_empty;                                                                      \
287         } else if ((__dlen__ <= AST_STRING_FIELD_ALLOCATION(*__p__)) ||                                                 \
288                    (!__ast_string_field_ptr_grow(&(x)->__field_mgr, &(x)->__field_mgr_pool, __dlen__, __p__)) ||        \
289                    (*__p__ = __ast_string_field_alloc_space(&(x)->__field_mgr, &(x)->__field_mgr_pool, __dlen__))) {    \
290                 if (*__p__ != (*ptr)) {                                                                                 \
291                         __ast_string_field_release_active((x)->__field_mgr_pool, (*ptr));                               \
292                 }                                                                                                       \
293                 memcpy((void *) *__p__, __d__, __dlen__);                                                               \
294         }                                                                                                               \
295         } while (0)
296
297 /*!
298   \brief Set a field to a simple string value
299   \param x Pointer to a structure containing fields
300   \param field Name of the field to set
301   \param data String value to be copied into the field
302   \return nothing
303 */
304 #define ast_string_field_set(x, field, data) do {               \
305         ast_string_field_ptr_set(x, &(x)->field, data);         \
306         } while (0)
307
308 /*!
309   \brief Set a field to a complex (built) value
310   \param x Pointer to a structure containing fields
311   \param ptr Pointer to a field within the structure
312   \param fmt printf-style format string
313   \param args Arguments for format string
314   \return nothing
315 */
316 #define ast_string_field_ptr_build(x, ptr, fmt, args...) \
317         __ast_string_field_ptr_build(&(x)->__field_mgr, &(x)->__field_mgr_pool, (ast_string_field *) ptr, fmt, args)
318
319 /*!
320   \brief Set a field to a complex (built) value
321   \param x Pointer to a structure containing fields
322   \param field Name of the field to set
323   \param fmt printf-style format string
324   \param args Arguments for format string
325   \return nothing
326 */
327 #define ast_string_field_build(x, field, fmt, args...) \
328         __ast_string_field_ptr_build(&(x)->__field_mgr, &(x)->__field_mgr_pool, (ast_string_field *) &(x)->field, fmt, args)
329
330 /*!
331   \brief Set a field to a complex (built) value with prebuilt va_lists.
332   \param x Pointer to a structure containing fields
333   \param ptr Pointer to a field within the structure
334   \param fmt printf-style format string
335   \param args1 Arguments for format string in va_list format
336   \param args2 a second copy of the va_list for the sake of bsd, with no va_list copy operation
337   \return nothing
338 */
339 #define ast_string_field_ptr_build_va(x, ptr, fmt, args1, args2) \
340         __ast_string_field_ptr_build_va(&(x)->__field_mgr, &(x)->__field_mgr_pool, (ast_string_field *) ptr, fmt, args1, args2)
341
342 /*!
343   \brief Set a field to a complex (built) value
344   \param x Pointer to a structure containing fields
345   \param field Name of the field to set
346   \param fmt printf-style format string
347   \param args1 argument one
348   \param args2 argument two
349   \return nothing
350 */
351 #define ast_string_field_build_va(x, field, fmt, args1, args2) \
352         __ast_string_field_ptr_build_va(&(x)->__field_mgr, &(x)->__field_mgr_pool, (ast_string_field *) &(x)->field, fmt, args1, args2)
353
354 #endif /* _ASTERISK_STRINGFIELDS_H */