1e6fe038cf3ed4e0d4c0cd31b4202cd205241d3f
[asterisk/asterisk.git] / include / asterisk / vector.h
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2013, Digium, Inc.
5  *
6  * David M. Lee, II <dlee@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 #ifndef _ASTERISK_VECTOR_H
20 #define _ASTERISK_VECTOR_H
21
22 #include "asterisk/lock.h"
23
24 /*! \file
25  *
26  * \brief Vector container support.
27  *
28  * A vector is a variable length array, with properties that can be useful when
29  * order doesn't matter.
30  *  - Appends are asymptotically constant time.
31  *  - Unordered removes are constant time.
32  *  - Search is linear time
33  *
34  * \author David M. Lee, II <dlee@digium.com>
35  * \since 12
36  */
37
38 /*!
39  * \brief Define a vector structure
40  *
41  * \param name Optional vector struct name.
42  * \param type Vector element type.
43  */
44 #define AST_VECTOR(name, type)                  \
45         struct name {                           \
46                 type *elems;                    \
47                 size_t max;                     \
48                 size_t current;                 \
49         }
50
51 /*! \brief Integer vector definition */
52 AST_VECTOR(ast_vector_int, int);
53
54 /*!
55  * \brief Define a vector structure with a read/write lock
56  *
57  * \param name Optional vector struct name.
58  * \param type Vector element type.
59  */
60 #define AST_VECTOR_RW(name, type) \
61         struct name {            \
62                 type *elems;         \
63                 size_t max;          \
64                 size_t current;      \
65                 ast_rwlock_t lock;   \
66         }
67
68 /*!
69  * \brief Initialize a vector
70  *
71  * If \a size is 0, then no space will be allocated until the vector is
72  * appended to.
73  *
74  * \param vec Vector to initialize.
75  * \param size Initial size of the vector.
76  *
77  * \return 0 on success.
78  * \return Non-zero on failure.
79  */
80 #define AST_VECTOR_INIT(vec, size) ({                                   \
81         size_t __size = (size);                                         \
82         size_t alloc_size = __size * sizeof(*((vec)->elems));           \
83         (vec)->elems = alloc_size ? ast_calloc(1, alloc_size) : NULL;   \
84         (vec)->current = 0;                                             \
85         if ((vec)->elems) {                                             \
86                 (vec)->max = __size;                                    \
87         } else {                                                        \
88                 (vec)->max = 0;                                         \
89         }                                                               \
90         (alloc_size == 0 || (vec)->elems != NULL) ? 0 : -1;             \
91 })
92
93 /*!
94  * \brief Initialize a vector with a read/write lock
95  *
96  * If \a size is 0, then no space will be allocated until the vector is
97  * appended to.
98  *
99  * \param vec Vector to initialize.
100  * \param size Initial size of the vector.
101  *
102  * \return 0 on success.
103  * \return Non-zero on failure.
104  */
105 #define AST_VECTOR_RW_INIT(vec, size) ({ \
106         int res = -1; \
107         if (AST_VECTOR_INIT(vec, size) == 0) { \
108                 res = ast_rwlock_init(&(vec)->lock); \
109         } \
110         res; \
111 })
112
113 /*!
114  * \brief Deallocates this vector.
115  *
116  * If any code to free the elements of this vector needs to be run, that should
117  * be done prior to this call.
118  *
119  * \param vec Vector to deallocate.
120  */
121 #define AST_VECTOR_FREE(vec) do {               \
122         ast_free((vec)->elems);                 \
123         (vec)->elems = NULL;                    \
124         (vec)->max = 0;                         \
125         (vec)->current = 0;                     \
126 } while (0)
127
128 /*!
129  * \brief Deallocates this vector pointer.
130  *
131  * If any code to free the elements of this vector need to be run, that should
132  * be done prior to this call.
133  *
134  * \param vec Pointer to a malloc'd vector structure.
135  */
136 #define AST_VECTOR_PTR_FREE(vec) do { \
137         AST_VECTOR_FREE(vec); \
138         ast_free(vec); \
139 } while (0)
140
141 /*!
142  * \brief Deallocates this locked vector
143  *
144  * If any code to free the elements of this vector need to be run, that should
145  * be done prior to this call.
146  *
147  * \param vec Vector to deallocate.
148  */
149 #define AST_VECTOR_RW_FREE(vec) do { \
150         AST_VECTOR_FREE(vec); \
151         ast_rwlock_destroy(&(vec)->lock); \
152 } while(0)
153
154 /*!
155  * \brief Deallocates this locked vector pointer.
156  *
157  * If any code to free the elements of this vector need to be run, that should
158  * be done prior to this call.
159  *
160  * \param vec Pointer to a malloc'd vector structure.
161  */
162 #define AST_VECTOR_RW_PTR_FREE(vec) do { \
163         AST_VECTOR_RW_FREE(vec); \
164         ast_free(vec); \
165 } while(0)
166
167 /*!
168  * \internal
169  */
170 #define __make_room(idx, vec) ({ \
171         int res = 0;                                                            \
172         do {                                                                                                            \
173                 if ((idx) >= (vec)->max) {                                                              \
174                         size_t new_max = ((idx) + 1) * 2;                               \
175                         typeof((vec)->elems) new_elems = ast_calloc(1,          \
176                                 new_max * sizeof(*new_elems));                                  \
177                         if (new_elems) {                                                                        \
178                                 if ((vec)->elems) {                                                             \
179                                         memcpy(new_elems, (vec)->elems,                         \
180                                                 (vec)->current * sizeof(*new_elems));   \
181                                         ast_free((vec)->elems);                                         \
182                                 }                                                                                               \
183                                 (vec)->elems = new_elems;                                               \
184                                 (vec)->max = new_max;                                                   \
185                         } else {                                                                                        \
186                                 res = -1;                                                                               \
187                                 break;                                                                                  \
188                         }                                                                                                       \
189                 }                                                                                                               \
190         } while(0);                                                                                                     \
191         res;                                                                                                            \
192 })
193
194 /*!
195  * \brief Append an element to a vector, growing the vector if needed.
196  *
197  * \param vec Vector to append to.
198  * \param elem Element to append.
199  *
200  * \return 0 on success.
201  * \return Non-zero on failure.
202  */
203 #define AST_VECTOR_APPEND(vec, elem) ({                                         \
204         int res = 0;                                                                                    \
205         do {                                                                                                    \
206                 if (__make_room((vec)->current, vec) != 0) {            \
207                         res = -1;                                                                               \
208                         break;                                                                                  \
209                 }                                                                                                       \
210                 (vec)->elems[(vec)->current++] = (elem);                        \
211         } while (0);                                                                                    \
212         res;                                                                                                    \
213 })
214
215 /*!
216  * \brief Replace an element at a specific position in a vector, growing the vector if needed.
217  *
218  * \param vec Vector to replace into.
219  * \param idx Position to replace.
220  * \param elem Element to replace.
221  *
222  * \return 0 on success.
223  * \return Non-zero on failure.
224  *
225  * \warning This macro will overwrite anything already present at the position provided.
226  *
227  * \warning Use of this macro with the expectation that the element will remain at the provided
228  * index means you can not use the UNORDERED assortment of macros. These macros alter the ordering
229  * of the vector itself.
230  */
231 #define AST_VECTOR_REPLACE(vec, idx, elem) ({           \
232         int res = 0;                                                                    \
233         do {                                                                                    \
234                 if (__make_room((idx), vec) != 0) {                     \
235                         res = -1;                                                               \
236                         break;                                                                  \
237                 }                                                                                       \
238                 (vec)->elems[(idx)] = (elem);                           \
239                 if (((idx) + 1) > (vec)->current) {                     \
240                         (vec)->current = (idx) + 1;                             \
241                 }                                                                                       \
242         } while(0);                                                                             \
243         res;                                                                                    \
244 })
245
246 /*!
247  * \brief Default a vector up to size with the given value.
248  *
249  * \note If a size of 0 is given then all elements in the given vector are set.
250  * \note The vector will grow to the given size if needed.
251  *
252  * \param vec Vector to default.
253  * \param size The number of elements to default
254  * \param value The default value to set each element to
255  */
256 #define AST_VECTOR_DEFAULT(vec, size, value) ({ \
257         int res = 0;                                                    \
258         typeof((size)) __size = (size) ? (size) : AST_VECTOR_SIZE(vec); \
259         size_t idx;                                                     \
260         for (idx = 0; idx < __size; ++idx) {                            \
261                 res = AST_VECTOR_REPLACE(vec, idx, value);              \
262                 if (res == -1) {                                        \
263                         break;                                          \
264                 }                                                       \
265         }                                                               \
266         res;                                                            \
267 })
268
269 /*!
270  * \brief Insert an element at a specific position in a vector, growing the vector if needed.
271  *
272  * \param vec Vector to insert into.
273  * \param idx Position to insert at.
274  * \param elem Element to insert.
275  *
276  * \return 0 on success.
277  * \return Non-zero on failure.
278  *
279  * \warning This macro will shift existing elements right to make room for the new element.
280  *
281  * \warning Use of this macro with the expectation that the element will remain at the provided
282  * index means you can not use the UNORDERED assortment of macros. These macros alter the ordering
283  * of the vector itself.
284  */
285 #define AST_VECTOR_INSERT_AT(vec, idx, elem) ({ \
286         int res = 0; \
287         size_t __move; \
288         do { \
289                 if (__make_room(((idx) > (vec)->current ? (idx) : (vec)->current), vec) != 0) {                                                 \
290                         res = -1;                                                                               \
291                         break;                                                                                  \
292                 }                                                                                                               \
293                 if ((vec)->current > 0 && (idx) < (vec)->current) { \
294                         __move = ((vec)->current - (idx)) * sizeof(typeof((vec)->elems[0])); \
295                         memmove(&(vec)->elems[(idx) + 1], &(vec)->elems[(idx)], __move); \
296                 } \
297                 (vec)->elems[(idx)] = (elem); \
298                 (vec)->current = ((idx) > (vec)->current ? (idx) : (vec)->current) + 1; \
299         } while (0); \
300         res; \
301 })
302
303 /*!
304  * \brief Add an element into a sorted vector
305  *
306  * \param vec Sorted vector to add to.
307  * \param elem Element to insert. Must not be an array type.
308  * \param cmp A strcmp compatible compare function.
309  *
310  * \return 0 on success.
311  * \return Non-zero on failure.
312  *
313  * \warning Use of this macro on an unsorted vector will produce unpredictable results
314  * \warning 'elem' must not be an array type so passing 'x' where 'x' is defined as
315  *          'char x[4]' will fail to compile. However casting 'x' as 'char *' does
316  *          result in a value that CAN be used.
317  */
318 #define AST_VECTOR_ADD_SORTED(vec, elem, cmp) ({ \
319         int res = 0; \
320         size_t __idx = (vec)->current; \
321         typeof(elem) __elem = (elem); \
322         do { \
323                 if (__make_room((vec)->current, vec) != 0) { \
324                         res = -1; \
325                         break; \
326                 } \
327                 while (__idx > 0 && (cmp((vec)->elems[__idx - 1], __elem) > 0)) { \
328                         (vec)->elems[__idx] = (vec)->elems[__idx - 1]; \
329                         __idx--; \
330                 } \
331                 (vec)->elems[__idx] = __elem; \
332                 (vec)->current++; \
333         } while (0); \
334         res; \
335 })
336
337 /*!
338  * \brief Remove an element from a vector by index.
339  *
340  * Note that elements in the vector may be reordered, so that the remove can
341  * happen in constant time.
342  *
343  * \param vec Vector to remove from.
344  * \param idx Index of the element to remove.
345  * \param preserve_order Preserve the vector order.
346  *
347  * \return The element that was removed.
348  */
349 #define AST_VECTOR_REMOVE(vec, idx, preserve_ordered) ({ \
350         typeof((vec)->elems[0]) res; \
351         size_t __idx = (idx); \
352         ast_assert(__idx < (vec)->current); \
353         res = (vec)->elems[__idx]; \
354         if ((preserve_ordered)) { \
355                 size_t __move; \
356                 __move = ((vec)->current - (__idx) - 1) * sizeof(typeof((vec)->elems[0])); \
357                 memmove(&(vec)->elems[__idx], &(vec)->elems[__idx + 1], __move); \
358                 (vec)->current--; \
359         } else { \
360                 (vec)->elems[__idx] = (vec)->elems[--(vec)->current];   \
361         }; \
362         res;                                                    \
363 })
364
365 /*!
366  * \brief Remove an element from an unordered vector by index.
367  *
368  * Note that elements in the vector may be reordered, so that the remove can
369  * happen in constant time.
370  *
371  * \param vec Vector to remove from.
372  * \param idx Index of the element to remove.
373  * \return The element that was removed.
374  */
375 #define AST_VECTOR_REMOVE_UNORDERED(vec, idx) \
376         AST_VECTOR_REMOVE(vec, idx, 0)
377
378 /*!
379  * \brief Remove an element from a vector by index while maintaining order.
380  *
381  * \param vec Vector to remove from.
382  * \param idx Index of the element to remove.
383  * \return The element that was removed.
384  */
385 #define AST_VECTOR_REMOVE_ORDERED(vec, idx) \
386         AST_VECTOR_REMOVE(vec, idx, 1)
387
388 /*!
389  * \brief Remove all elements from a vector that matches the given comparison
390  *
391  * \param vec Vector to remove from.
392  * \param value Value to pass into comparator.
393  * \param cmp Comparator function/macros (called as \c cmp(elem, value))
394  * \param cleanup How to cleanup a removed element macro/function.
395  *
396  * \return the number of deleted elements.
397  */
398 #define AST_VECTOR_REMOVE_ALL_CMP_UNORDERED(vec, value, cmp, cleanup) ({        \
399         int count = 0;                                                  \
400         size_t idx;                                                     \
401         typeof(value) __value = (value);                                \
402         for (idx = 0; idx < (vec)->current; ) {                         \
403                 if (cmp((vec)->elems[idx], __value)) {                  \
404                         cleanup((vec)->elems[idx]);                     \
405                         AST_VECTOR_REMOVE_UNORDERED((vec), idx);        \
406                         ++count;                                        \
407                 } else {                                                \
408                         ++idx;                                          \
409                 }                                                       \
410         }                                                               \
411         count;                                                          \
412 })
413
414 /*!
415  * \brief Remove an element from a vector that matches the given comparison
416  *
417  * \param vec Vector to remove from.
418  * \param value Value to pass into comparator.
419  * \param cmp Comparator function/macros (called as \c cmp(elem, value))
420  * \param cleanup How to cleanup a removed element macro/function.
421  *
422  * \return 0 if element was removed.
423  * \return Non-zero if element was not in the vector.
424  */
425 #define AST_VECTOR_REMOVE_CMP_UNORDERED(vec, value, cmp, cleanup) ({    \
426         int res = -1;                                                   \
427         size_t idx;                                                     \
428         typeof(value) __value = (value);                                \
429         for (idx = 0; idx < (vec)->current; ++idx) {                    \
430                 if (cmp((vec)->elems[idx], __value)) {                  \
431                         cleanup((vec)->elems[idx]);                     \
432                         AST_VECTOR_REMOVE_UNORDERED((vec), idx);        \
433                         res = 0;                                        \
434                         break;                                          \
435                 }                                                       \
436         }                                                               \
437         res;                                                            \
438 })
439
440 /*!
441  * \brief Remove all elements from a vector that matches the given comparison while maintaining order
442  *
443  * \param vec Vector to remove from.
444  * \param value Value to pass into comparator.
445  * \param cmp Comparator function/macros (called as \c cmp(elem, value))
446  * \param cleanup How to cleanup a removed element macro/function.
447  *
448  * \return the number of deleted elements.
449  */
450 #define AST_VECTOR_REMOVE_ALL_CMP_ORDERED(vec, value, cmp, cleanup) ({  \
451         int count = 0;                                                  \
452         size_t idx;                                                     \
453         typeof(value) __value = (value);                                \
454         for (idx = 0; idx < (vec)->current; ) {                         \
455                 if (cmp((vec)->elems[idx], __value)) {                  \
456                         cleanup((vec)->elems[idx]);                     \
457                         AST_VECTOR_REMOVE_ORDERED((vec), idx);          \
458                         ++count;                                        \
459                 } else {                                                \
460                         ++idx;                                          \
461                 }                                                       \
462         }                                                               \
463         count;                                                          \
464 })
465
466 /*!
467  * \brief Remove an element from a vector that matches the given comparison while maintaining order
468  *
469  * \param vec Vector to remove from.
470  * \param value Value to pass into comparator.
471  * \param cmp Comparator function/macros (called as \c cmp(elem, value))
472  * \param cleanup How to cleanup a removed element macro/function.
473  *
474  * \return 0 if element was removed.
475  * \return Non-zero if element was not in the vector.
476  */
477 #define AST_VECTOR_REMOVE_CMP_ORDERED(vec, value, cmp, cleanup) ({      \
478         int res = -1;                                                   \
479         size_t idx;                                                     \
480         typeof(value) __value = (value);                                \
481         for (idx = 0; idx < (vec)->current; ++idx) {                    \
482                 if (cmp((vec)->elems[idx], __value)) {                  \
483                         cleanup((vec)->elems[idx]);                     \
484                         AST_VECTOR_REMOVE_ORDERED((vec), idx);          \
485                         res = 0;                                        \
486                         break;                                          \
487                 }                                                       \
488         }                                                               \
489         res;                                                            \
490 })
491
492 /*!
493  * \brief Default comparator for AST_VECTOR_REMOVE_ELEM_UNORDERED()
494  *
495  * \param elem Element to compare against
496  * \param value Value to compare with the vector element.
497  *
498  * \return 0 if element does not match.
499  * \return Non-zero if element matches.
500  */
501 #define AST_VECTOR_ELEM_DEFAULT_CMP(elem, value) ((elem) == (value))
502
503 /*!
504  * \brief Vector element cleanup that does nothing.
505  *
506  * \param elem Element to cleanup
507  *
508  * \return Nothing
509  */
510 #define AST_VECTOR_ELEM_CLEANUP_NOOP(elem)
511
512 /*!
513  * \brief Remove an element from a vector.
514  *
515  * \param vec Vector to remove from.
516  * \param elem Element to remove
517  * \param cleanup How to cleanup a removed element macro/function.
518  *
519  * \return 0 if element was removed.
520  * \return Non-zero if element was not in the vector.
521  */
522 #define AST_VECTOR_REMOVE_ELEM_UNORDERED(vec, elem, cleanup) ({ \
523         AST_VECTOR_REMOVE_CMP_UNORDERED((vec), (elem),          \
524                 AST_VECTOR_ELEM_DEFAULT_CMP, cleanup);          \
525 })
526
527 /*!
528  * \brief Remove an element from a vector while maintaining order.
529  *
530  * \param vec Vector to remove from.
531  * \param elem Element to remove
532  * \param cleanup How to cleanup a removed element macro/function.
533  *
534  * \return 0 if element was removed.
535  * \return Non-zero if element was not in the vector.
536  */
537 #define AST_VECTOR_REMOVE_ELEM_ORDERED(vec, elem, cleanup) ({   \
538         AST_VECTOR_REMOVE_CMP_ORDERED((vec), (elem),            \
539                 AST_VECTOR_ELEM_DEFAULT_CMP, cleanup);          \
540 })
541
542 /*!
543  * \brief Get the number of elements in a vector.
544  *
545  * \param vec Vector to query.
546  * \return Number of elements in the vector.
547  */
548 #define AST_VECTOR_SIZE(vec) (vec)->current
549
550 /*!
551  * \brief Reset vector.
552  *
553  * \param vec Vector to reset.
554  * \param callback A cleanup callback or AST_VECTOR_ELEM_CLEANUP_NOOP.
555  */
556 #define AST_VECTOR_RESET(vec, cleanup) ({ \
557         AST_VECTOR_CALLBACK_VOID(vec, cleanup); \
558         (vec)->current = 0; \
559 })
560
561 /*!
562  * \brief Get an address of element in a vector.
563  *
564  * \param vec Vector to query.
565  * \param idx Index of the element to get address of.
566  */
567 #define AST_VECTOR_GET_ADDR(vec, idx) ({        \
568         size_t __idx = (idx);                   \
569         ast_assert(__idx < (vec)->current);     \
570         &(vec)->elems[__idx];                   \
571 })
572
573 /*!
574  * \brief Get an element from a vector.
575  *
576  * \param vec Vector to query.
577  * \param idx Index of the element to get.
578  */
579 #define AST_VECTOR_GET(vec, idx) ({             \
580         size_t __idx = (idx);                   \
581         ast_assert(__idx < (vec)->current);     \
582         (vec)->elems[__idx];                    \
583 })
584
585 /*!
586  * \brief Get the nth index from a vector that matches the given comparison
587  *
588  * \param vec Vector to get from.
589  * \param nth The nth index to find
590  * \param value Value to pass into comparator.
591  * \param cmp Comparator function/macros (called as \c cmp(elem, value))
592  *
593  * \return a pointer to the element that was found or NULL
594  */
595 #define AST_VECTOR_GET_INDEX_NTH(vec, nth, value, cmp) ({ \
596         int res = -1; \
597         size_t idx; \
598         typeof(nth) __nth = (nth); \
599         typeof(value) __value = (value); \
600         for (idx = 0; idx < (vec)->current; ++idx) { \
601                 if (cmp((vec)->elems[idx], __value) && !(--__nth)) {    \
602                         res = (int)idx;                                 \
603                         break; \
604                 } \
605         } \
606         res; \
607 })
608
609 /*!
610  * \brief Get the 1st index from a vector that matches the given comparison
611  *
612  * \param vec Vector to get from.
613  * \param value Value to pass into comparator.
614  * \param cmp Comparator function/macros (called as \c cmp(elem, value))
615  *
616  * \return a pointer to the element that was found or NULL
617  */
618 #define AST_VECTOR_GET_INDEX(vec, value, cmp) \
619         AST_VECTOR_GET_INDEX_NTH(vec, 1, value, cmp)
620
621 /*!
622  * \brief Get an element from a vector that matches the given comparison
623  *
624  * \param vec Vector to get from.
625  * \param value Value to pass into comparator.
626  * \param cmp Comparator function/macros (called as \c cmp(elem, value))
627  *
628  * \return a pointer to the element that was found or NULL
629  */
630 #define AST_VECTOR_GET_CMP(vec, value, cmp) ({ \
631         void *res = NULL; \
632         size_t idx; \
633         typeof(value) __value = (value); \
634         for (idx = 0; idx < (vec)->current; ++idx) { \
635                 if (cmp((vec)->elems[idx], __value)) { \
636                         res = &(vec)->elems[idx]; \
637                         break; \
638                 } \
639         } \
640         res; \
641 })
642
643 /*!
644  * \brief Default callback for AST_VECTOR_CALLBACK()
645  *
646  * \param elem Element to compare against
647  * \param value Value to compare with the vector element.
648  *
649  * \return CMP_MATCH always.
650  */
651 #define AST_VECTOR_MATCH_ALL(element) (CMP_MATCH)
652
653
654 /*!
655  * \brief Execute a callback on every element in a vector returning the first matched
656  *
657  * \param vec Vector to operate on.
658  * \param callback A callback that takes at least 1 argument (the element)
659  * plus number of optional arguments
660  * \param default_value A default value to return if no elements matched
661  *
662  * \return the first element matched before CMP_STOP was returned
663  * or the end of the vector was reached. Otherwise, default_value
664  */
665 #define AST_VECTOR_CALLBACK(vec, callback, default_value, ...) ({ \
666         size_t idx; \
667         typeof((vec)->elems[0]) res = default_value;                            \
668         for (idx = 0; idx < (vec)->current; idx++) { \
669                 int rc = callback((vec)->elems[idx], ##__VA_ARGS__);    \
670                 if (rc & CMP_MATCH) { \
671                         res = (vec)->elems[idx]; \
672                         break; \
673                 }\
674                 if (rc & CMP_STOP) { \
675                         break; \
676                 }\
677         } \
678         res; \
679 })
680
681 /*!
682  * \brief Execute a callback on every element in a vector returning the matching
683  * elements in a new vector
684  *
685  * This macro basically provides a filtered clone.
686  *
687  * \param vec Vector to operate on.
688  * \param callback A callback that takes at least 1 argument (the element)
689  * plus number of optional arguments
690  *
691  * \return a vector containing the elements matched before CMP_STOP was returned
692  * or the end of the vector was reached. The vector may be empty and could be NULL
693  * if there was not enough memory to allocate it's control structure.
694  *
695  * \warning The returned vector must have AST_VECTOR_PTR_FREE()
696  * called on it after you've finished with it.
697  *
698  * \note The type of the returned vector must be traceable to the original vector.
699  *
700  * The following will resut in "error: assignment from incompatible pointer type"
701  * because these declare 2 different structures.
702  *
703  * \code
704  * AST_VECTOR(, char *) vector_1;
705  * AST_VECTOR(, char *) *vector_2;
706  *
707  * vector_2 = AST_VECTOR_CALLBACK_MULTIPLE(&vector_1, callback);
708  * \endcode
709  *
710  * This will work because you're using the type of the first
711  * to declare the second:
712  *
713  * \code
714  * AST_VECTOR(mytype, char *) vector_1;
715  * struct mytype *vector_2 = NULL;
716  *
717  * vector_2 = AST_VECTOR_CALLBACK_MULTIPLE(&vector_1, callback);
718  * \endcode
719  *
720  * This will also work because you're declaring both vector_1 and
721  * vector_2 from the same definition.
722  *
723  * \code
724  * AST_VECTOR(, char *) vector_1, *vector_2 = NULL;
725  *
726  * vector_2 = AST_VECTOR_CALLBACK_MULTIPLE(&vector_1, callback);
727  * \endcode
728  */
729 #define AST_VECTOR_CALLBACK_MULTIPLE(vec, callback, ...) ({ \
730         size_t idx; \
731         typeof((vec)) new_vec; \
732         do { \
733                 new_vec = ast_malloc(sizeof(*new_vec)); \
734                 if (!new_vec) { \
735                         break; \
736                 } \
737                 if (AST_VECTOR_INIT(new_vec, AST_VECTOR_SIZE((vec))) != 0) { \
738                         ast_free(new_vec); \
739                         new_vec = NULL; \
740                         break; \
741                 } \
742                 for (idx = 0; idx < (vec)->current; idx++) { \
743                         int rc = callback((vec)->elems[idx], ##__VA_ARGS__);    \
744                         if (rc & CMP_MATCH) { \
745                                 AST_VECTOR_APPEND(new_vec, (vec)->elems[idx]); \
746                         } \
747                         if (rc & CMP_STOP) { \
748                                 break; \
749                         }\
750                 } \
751         } while(0); \
752         new_vec; \
753 })
754
755 /*!
756  * \brief Execute a callback on every element in a vector disregarding callback return
757  *
758  * \param vec Vector to operate on.
759  * \param callback A callback that takes at least 1 argument (the element)
760  * plus number of optional arguments
761  */
762 #define AST_VECTOR_CALLBACK_VOID(vec, callback, ...) ({ \
763         size_t idx; \
764         for (idx = 0; idx < (vec)->current; idx++) { \
765                 callback((vec)->elems[idx], ##__VA_ARGS__);     \
766         } \
767 })
768
769 /*!
770  * \brief Obtain read lock on vector
771  *
772  * \param vec Vector to operate on.
773  *
774  * \return 0 if success
775  * \return Non-zero if error
776  */
777 #define AST_VECTOR_RW_RDLOCK(vec) ast_rwlock_rdlock(&(vec)->lock)
778
779 /*!
780  * \brief Obtain write lock on vector
781  *
782  * \param vec Vector to operate on.
783  *
784  * \return 0 if success
785  * \return Non-zero if error
786  */
787 #define AST_VECTOR_RW_WRLOCK(vec) ast_rwlock_wrlock(&(vec)->lock)
788
789 /*!
790  * \brief Unlock vector
791  *
792  * \param vec Vector to operate on.
793  *
794  * \return 0 if success
795  * \return Non-zero if error
796  */
797 #define AST_VECTOR_RW_UNLOCK(vec) ast_rwlock_unlock(&(vec)->lock)
798
799 /*!
800  * \brief Try to obtain read lock on vector failing immediately if unable
801  *
802  * \param vec Vector to operate on.
803  *
804  * \return 0 if success
805  * \return Non-zero if error
806  */
807 #define AST_VECTOR_RW_RDLOCK_TRY(vec) ast_rwlock_tryrdlock(&(vec)->lock)
808
809 /*!
810  * \brief Try to obtain write lock on vector failing immediately if unable
811  *
812  * \param vec Vector to operate on.
813  *
814  * \return 0 if success
815  * \return Non-zero if error
816  */
817 #define AST_VECTOR_RW_WRLOCK_TRY(vec) ast_rwlock_trywrlock(&(vec)->lock)
818
819 /*!
820  * \brief Try to obtain read lock on vector failing after timeout if unable
821  *
822  * \param vec Vector to operate on.
823  *
824  * \return 0 if success
825  * \return Non-zero if error
826  */
827 #define AST_VECTOR_RW_RDLOCK_TIMED(vec, timespec) ast_rwlock_timedrdlock(&(vec)->lock, timespec)
828
829 /*!
830  * \brief Try to obtain write lock on vector failing after timeout if unable
831  *
832  * \param vec Vector to operate on.
833  *
834  * \return 0 if success
835  * \return Non-zero if error
836  */
837 #define AST_VECTOR_RW_WRLOCK_TIMED(vec, timespec) ast_rwlock_timedwrlock(&(vec)->lock, timespec)
838
839 #endif /* _ASTERISK_VECTOR_H */