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