res_pjsip_registrar.c: Update remove_existing AOR contact handling.
[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 Get the maximum number of elements the vector can currently hold.
552  *
553  * \param vec Vector to query.
554  * \return Maximum number of elements the vector can currently hold.
555  */
556 #define AST_VECTOR_MAX_SIZE(vec) (vec)->max
557
558 /*!
559  * \brief Reset vector.
560  *
561  * \param vec Vector to reset.
562  * \param callback A cleanup callback or AST_VECTOR_ELEM_CLEANUP_NOOP.
563  */
564 #define AST_VECTOR_RESET(vec, cleanup) ({ \
565         AST_VECTOR_CALLBACK_VOID(vec, cleanup); \
566         (vec)->current = 0; \
567 })
568
569 /*!
570  * \brief Get an address of element in a vector.
571  *
572  * \param vec Vector to query.
573  * \param idx Index of the element to get address of.
574  */
575 #define AST_VECTOR_GET_ADDR(vec, idx) ({        \
576         size_t __idx = (idx);                   \
577         ast_assert(__idx < (vec)->current);     \
578         &(vec)->elems[__idx];                   \
579 })
580
581 /*!
582  * \brief Get an element from a vector.
583  *
584  * \param vec Vector to query.
585  * \param idx Index of the element to get.
586  */
587 #define AST_VECTOR_GET(vec, idx) ({             \
588         size_t __idx = (idx);                   \
589         ast_assert(__idx < (vec)->current);     \
590         (vec)->elems[__idx];                    \
591 })
592
593 /*!
594  * \brief Get the nth index from a vector that matches the given comparison
595  *
596  * \param vec Vector to get from.
597  * \param nth The nth index to find
598  * \param value Value to pass into comparator.
599  * \param cmp Comparator function/macros (called as \c cmp(elem, value))
600  *
601  * \return a pointer to the element that was found or NULL
602  */
603 #define AST_VECTOR_GET_INDEX_NTH(vec, nth, value, cmp) ({ \
604         int res = -1; \
605         size_t idx; \
606         typeof(nth) __nth = (nth); \
607         typeof(value) __value = (value); \
608         for (idx = 0; idx < (vec)->current; ++idx) { \
609                 if (cmp((vec)->elems[idx], __value) && !(--__nth)) {    \
610                         res = (int)idx;                                 \
611                         break; \
612                 } \
613         } \
614         res; \
615 })
616
617 /*!
618  * \brief Get the 1st index from a vector that matches the given comparison
619  *
620  * \param vec Vector to get from.
621  * \param value Value to pass into comparator.
622  * \param cmp Comparator function/macros (called as \c cmp(elem, value))
623  *
624  * \return a pointer to the element that was found or NULL
625  */
626 #define AST_VECTOR_GET_INDEX(vec, value, cmp) \
627         AST_VECTOR_GET_INDEX_NTH(vec, 1, value, cmp)
628
629 /*!
630  * \brief Get an element from a vector that matches the given comparison
631  *
632  * \param vec Vector to get from.
633  * \param value Value to pass into comparator.
634  * \param cmp Comparator function/macros (called as \c cmp(elem, value))
635  *
636  * \return a pointer to the element that was found or NULL
637  */
638 #define AST_VECTOR_GET_CMP(vec, value, cmp) ({ \
639         void *res = NULL; \
640         size_t idx; \
641         typeof(value) __value = (value); \
642         for (idx = 0; idx < (vec)->current; ++idx) { \
643                 if (cmp((vec)->elems[idx], __value)) { \
644                         res = &(vec)->elems[idx]; \
645                         break; \
646                 } \
647         } \
648         res; \
649 })
650
651 /*!
652  * \brief Default callback for AST_VECTOR_CALLBACK()
653  *
654  * \param elem Element to compare against
655  * \param value Value to compare with the vector element.
656  *
657  * \return CMP_MATCH always.
658  */
659 #define AST_VECTOR_MATCH_ALL(element) (CMP_MATCH)
660
661
662 /*!
663  * \brief Execute a callback on every element in a vector returning the first matched
664  *
665  * \param vec Vector to operate on.
666  * \param callback A callback that takes at least 1 argument (the element)
667  * plus number of optional arguments
668  * \param default_value A default value to return if no elements matched
669  *
670  * \return the first element matched before CMP_STOP was returned
671  * or the end of the vector was reached. Otherwise, default_value
672  */
673 #define AST_VECTOR_CALLBACK(vec, callback, default_value, ...) ({ \
674         size_t idx; \
675         typeof((vec)->elems[0]) res = default_value;                            \
676         for (idx = 0; idx < (vec)->current; idx++) { \
677                 int rc = callback((vec)->elems[idx], ##__VA_ARGS__);    \
678                 if (rc & CMP_MATCH) { \
679                         res = (vec)->elems[idx]; \
680                         break; \
681                 }\
682                 if (rc & CMP_STOP) { \
683                         break; \
684                 }\
685         } \
686         res; \
687 })
688
689 /*!
690  * \brief Execute a callback on every element in a vector returning the matching
691  * elements in a new vector
692  *
693  * This macro basically provides a filtered clone.
694  *
695  * \param vec Vector to operate on.
696  * \param callback A callback that takes at least 1 argument (the element)
697  * plus number of optional arguments
698  *
699  * \return a vector containing the elements matched before CMP_STOP was returned
700  * or the end of the vector was reached. The vector may be empty and could be NULL
701  * if there was not enough memory to allocate it's control structure.
702  *
703  * \warning The returned vector must have AST_VECTOR_PTR_FREE()
704  * called on it after you've finished with it.
705  *
706  * \note The type of the returned vector must be traceable to the original vector.
707  *
708  * The following will resut in "error: assignment from incompatible pointer type"
709  * because these declare 2 different structures.
710  *
711  * \code
712  * AST_VECTOR(, char *) vector_1;
713  * AST_VECTOR(, char *) *vector_2;
714  *
715  * vector_2 = AST_VECTOR_CALLBACK_MULTIPLE(&vector_1, callback);
716  * \endcode
717  *
718  * This will work because you're using the type of the first
719  * to declare the second:
720  *
721  * \code
722  * AST_VECTOR(mytype, char *) vector_1;
723  * struct mytype *vector_2 = NULL;
724  *
725  * vector_2 = AST_VECTOR_CALLBACK_MULTIPLE(&vector_1, callback);
726  * \endcode
727  *
728  * This will also work because you're declaring both vector_1 and
729  * vector_2 from the same definition.
730  *
731  * \code
732  * AST_VECTOR(, char *) vector_1, *vector_2 = NULL;
733  *
734  * vector_2 = AST_VECTOR_CALLBACK_MULTIPLE(&vector_1, callback);
735  * \endcode
736  */
737 #define AST_VECTOR_CALLBACK_MULTIPLE(vec, callback, ...) ({ \
738         size_t idx; \
739         typeof((vec)) new_vec; \
740         do { \
741                 new_vec = ast_malloc(sizeof(*new_vec)); \
742                 if (!new_vec) { \
743                         break; \
744                 } \
745                 if (AST_VECTOR_INIT(new_vec, AST_VECTOR_SIZE((vec))) != 0) { \
746                         ast_free(new_vec); \
747                         new_vec = NULL; \
748                         break; \
749                 } \
750                 for (idx = 0; idx < (vec)->current; idx++) { \
751                         int rc = callback((vec)->elems[idx], ##__VA_ARGS__);    \
752                         if (rc & CMP_MATCH) { \
753                                 AST_VECTOR_APPEND(new_vec, (vec)->elems[idx]); \
754                         } \
755                         if (rc & CMP_STOP) { \
756                                 break; \
757                         }\
758                 } \
759         } while(0); \
760         new_vec; \
761 })
762
763 /*!
764  * \brief Execute a callback on every element in a vector disregarding callback return
765  *
766  * \param vec Vector to operate on.
767  * \param callback A callback that takes at least 1 argument (the element)
768  * plus number of optional arguments
769  */
770 #define AST_VECTOR_CALLBACK_VOID(vec, callback, ...) ({ \
771         size_t idx; \
772         for (idx = 0; idx < (vec)->current; idx++) { \
773                 callback((vec)->elems[idx], ##__VA_ARGS__);     \
774         } \
775 })
776
777 /*!
778  * \brief Obtain read lock on vector
779  *
780  * \param vec Vector to operate on.
781  *
782  * \return 0 if success
783  * \return Non-zero if error
784  */
785 #define AST_VECTOR_RW_RDLOCK(vec) ast_rwlock_rdlock(&(vec)->lock)
786
787 /*!
788  * \brief Obtain write lock on vector
789  *
790  * \param vec Vector to operate on.
791  *
792  * \return 0 if success
793  * \return Non-zero if error
794  */
795 #define AST_VECTOR_RW_WRLOCK(vec) ast_rwlock_wrlock(&(vec)->lock)
796
797 /*!
798  * \brief Unlock vector
799  *
800  * \param vec Vector to operate on.
801  *
802  * \return 0 if success
803  * \return Non-zero if error
804  */
805 #define AST_VECTOR_RW_UNLOCK(vec) ast_rwlock_unlock(&(vec)->lock)
806
807 /*!
808  * \brief Try to obtain read lock on vector failing immediately if unable
809  *
810  * \param vec Vector to operate on.
811  *
812  * \return 0 if success
813  * \return Non-zero if error
814  */
815 #define AST_VECTOR_RW_RDLOCK_TRY(vec) ast_rwlock_tryrdlock(&(vec)->lock)
816
817 /*!
818  * \brief Try to obtain write lock on vector failing immediately if unable
819  *
820  * \param vec Vector to operate on.
821  *
822  * \return 0 if success
823  * \return Non-zero if error
824  */
825 #define AST_VECTOR_RW_WRLOCK_TRY(vec) ast_rwlock_trywrlock(&(vec)->lock)
826
827 /*!
828  * \brief Try to obtain read lock on vector failing after timeout if unable
829  *
830  * \param vec Vector to operate on.
831  *
832  * \return 0 if success
833  * \return Non-zero if error
834  */
835 #define AST_VECTOR_RW_RDLOCK_TIMED(vec, timespec) ast_rwlock_timedrdlock(&(vec)->lock, timespec)
836
837 /*!
838  * \brief Try to obtain write lock on vector failing after timeout if unable
839  *
840  * \param vec Vector to operate on.
841  *
842  * \return 0 if success
843  * \return Non-zero if error
844  */
845 #define AST_VECTOR_RW_WRLOCK_TIMED(vec, timespec) ast_rwlock_timedwrlock(&(vec)->lock, timespec)
846
847 #endif /* _ASTERISK_VECTOR_H */