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