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