Asterisk - The Open Source Telephony Project  18.5.0
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 <[email protected]>
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 <[email protected]>
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 definitions */
55 AST_VECTOR(ast_vector_string, char *);
56 AST_VECTOR(ast_vector_const_string, const char *);
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 enum 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  */
83 int ast_vector_string_split(struct ast_vector_string *dest,
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  * \return 0 on success.
111  * \return 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  * \return 0 on success.
156  * \return 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  * \return 0 on success.
254  * \return 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  * \return 0 on success.
276  * \return 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  * \return 0 on success.
330  * \return 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  * \return 0 on success.
364  * \return 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_order 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  * \return 0 if element was removed.
486  * \return 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  * \return 0 if element was removed.
538  * \return 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  * \return 0 if element does not match.
562  * \return 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  * \return Nothing
572  */
573 #define AST_VECTOR_ELEM_CLEANUP_NOOP(elem)
574 
575 /*!
576  * \brief Remove an element from a vector.
577  *
578  * \param vec Vector to remove from.
579  * \param elem Element to remove
580  * \param cleanup How to cleanup a removed element macro/function.
581  *
582  * \return 0 if element was removed.
583  * \return Non-zero if element was not in the vector.
584  */
585 #define AST_VECTOR_REMOVE_ELEM_UNORDERED(vec, elem, cleanup) ({ \
586  AST_VECTOR_REMOVE_CMP_UNORDERED((vec), (elem), \
587  AST_VECTOR_ELEM_DEFAULT_CMP, cleanup); \
588 })
589 
590 /*!
591  * \brief Remove an element from a vector while maintaining order.
592  *
593  * \param vec Vector to remove from.
594  * \param elem Element to remove
595  * \param cleanup How to cleanup a removed element macro/function.
596  *
597  * \return 0 if element was removed.
598  * \return Non-zero if element was not in the vector.
599  */
600 #define AST_VECTOR_REMOVE_ELEM_ORDERED(vec, elem, cleanup) ({ \
601  AST_VECTOR_REMOVE_CMP_ORDERED((vec), (elem), \
602  AST_VECTOR_ELEM_DEFAULT_CMP, cleanup); \
603 })
604 
605 /*!
606  * \brief Get the number of elements in a vector.
607  *
608  * \param vec Vector to query.
609  * \return Number of elements in the vector.
610  */
611 #define AST_VECTOR_SIZE(vec) (vec)->current
612 
613 /*!
614  * \brief Get the maximum number of elements the vector can currently hold.
615  *
616  * \param vec Vector to query.
617  * \return Maximum number of elements the vector can currently hold.
618  */
619 #define AST_VECTOR_MAX_SIZE(vec) (vec)->max
620 
621 /*!
622  * \brief Reset vector.
623  *
624  * \param vec Vector to reset.
625  * \param callback A cleanup callback or AST_VECTOR_ELEM_CLEANUP_NOOP.
626  */
627 #define AST_VECTOR_RESET(vec, cleanup) ({ \
628  AST_VECTOR_CALLBACK_VOID(vec, cleanup); \
629  (vec)->current = 0; \
630 })
631 
632 /*!
633  * \brief Resize a vector so that its capacity is the same as its size.
634  *
635  * \param vec Vector to compact.
636  *
637  * \return 0 on success.
638  * \return Non-zero on failure.
639  */
640 #define AST_VECTOR_COMPACT(vec) ({ \
641  int res = 0; \
642  do { \
643  size_t new_max = (vec)->current; \
644  if (new_max == 0) { \
645  ast_free((vec)->elems); \
646  (vec)->elems = NULL; \
647  (vec)->max = 0; \
648  } else if ((vec)->max > new_max) { \
649  typeof((vec)->elems) new_elems = ast_realloc( \
650  (vec)->elems, \
651  new_max * sizeof(*new_elems)); \
652  if (new_elems) { \
653  (vec)->elems = new_elems; \
654  (vec)->max = new_max; \
655  } else { \
656  res = -1; \
657  break; \
658  } \
659  } \
660  } while(0); \
661  res; \
662 })
663 
664 /*!
665  * \brief Get an address of element in a vector.
666  *
667  * \param vec Vector to query.
668  * \param idx Index of the element to get address of.
669  */
670 #define AST_VECTOR_GET_ADDR(vec, idx) ({ \
671  size_t __idx = (idx); \
672  ast_assert(__idx < (vec)->current); \
673  &(vec)->elems[__idx]; \
674 })
675 
676 /*!
677  * \brief Get an element from a vector.
678  *
679  * \param vec Vector to query.
680  * \param idx Index of the element to get.
681  */
682 #define AST_VECTOR_GET(vec, idx) ({ \
683  size_t __idx = (idx); \
684  ast_assert(__idx < (vec)->current); \
685  (vec)->elems[__idx]; \
686 })
687 
688 /*!
689  * \brief Get the nth index from a vector that matches the given comparison
690  *
691  * \param vec Vector to get from.
692  * \param nth The nth index to find
693  * \param value Value to pass into comparator.
694  * \param cmp Comparator function/macros (called as \c cmp(elem, value))
695  *
696  * \return a pointer to the element that was found or NULL
697  */
698 #define AST_VECTOR_GET_INDEX_NTH(vec, nth, value, cmp) ({ \
699  int res = -1; \
700  size_t idx; \
701  typeof(nth) __nth = (nth); \
702  typeof(value) __value = (value); \
703  for (idx = 0; idx < (vec)->current; ++idx) { \
704  if (cmp((vec)->elems[idx], __value) && !(--__nth)) { \
705  res = (int)idx; \
706  break; \
707  } \
708  } \
709  res; \
710 })
711 
712 /*!
713  * \brief Get the 1st index from a vector that matches the given comparison
714  *
715  * \param vec Vector to get from.
716  * \param value Value to pass into comparator.
717  * \param cmp Comparator function/macros (called as \c cmp(elem, value))
718  *
719  * \return a pointer to the element that was found or NULL
720  */
721 #define AST_VECTOR_GET_INDEX(vec, value, cmp) \
722  AST_VECTOR_GET_INDEX_NTH(vec, 1, value, cmp)
723 
724 /*!
725  * \brief Get an element from a vector that matches the given comparison
726  *
727  * \param vec Vector to get from.
728  * \param value Value to pass into comparator.
729  * \param cmp Comparator function/macros (called as \c cmp(elem, value))
730  *
731  * \return a pointer to the element that was found or NULL
732  */
733 #define AST_VECTOR_GET_CMP(vec, value, cmp) ({ \
734  void *res = NULL; \
735  size_t idx; \
736  typeof(value) __value = (value); \
737  for (idx = 0; idx < (vec)->current; ++idx) { \
738  if (cmp((vec)->elems[idx], __value)) { \
739  res = &(vec)->elems[idx]; \
740  break; \
741  } \
742  } \
743  res; \
744 })
745 
746 /*!
747  * \brief Default callback for AST_VECTOR_CALLBACK()
748  *
749  * \param elem Element to compare against
750  * \param value Value to compare with the vector element.
751  *
752  * \return CMP_MATCH always.
753  */
754 #define AST_VECTOR_MATCH_ALL(element) (CMP_MATCH)
755 
756 
757 /*!
758  * \brief Execute a callback on every element in a vector returning the first matched
759  *
760  * \param vec Vector to operate on.
761  * \param callback A callback that takes at least 1 argument (the element)
762  * plus number of optional arguments
763  * \param default_value A default value to return if no elements matched
764  *
765  * \return the first element matched before CMP_STOP was returned
766  * or the end of the vector was reached. Otherwise, default_value
767  */
768 #define AST_VECTOR_CALLBACK(vec, callback, default_value, ...) ({ \
769  size_t idx; \
770  typeof((vec)->elems[0]) res = default_value; \
771  for (idx = 0; idx < (vec)->current; idx++) { \
772  int rc = callback((vec)->elems[idx], ##__VA_ARGS__); \
773  if (rc & CMP_MATCH) { \
774  res = (vec)->elems[idx]; \
775  break; \
776  }\
777  if (rc & CMP_STOP) { \
778  break; \
779  }\
780  } \
781  res; \
782 })
783 
784 /*!
785  * \brief Execute a callback on every element in a vector returning the matching
786  * elements in a new vector
787  *
788  * This macro basically provides a filtered clone.
789  *
790  * \param vec Vector to operate on.
791  * \param callback A callback that takes at least 1 argument (the element)
792  * plus number of optional arguments
793  *
794  * \return a vector containing the elements matched before CMP_STOP was returned
795  * or the end of the vector was reached. The vector may be empty and could be NULL
796  * if there was not enough memory to allocate it's control structure.
797  *
798  * \warning The returned vector must have AST_VECTOR_PTR_FREE()
799  * called on it after you've finished with it.
800  *
801  * \note The type of the returned vector must be traceable to the original vector.
802  *
803  * The following will resut in "error: assignment from incompatible pointer type"
804  * because these declare 2 different structures.
805  *
806  * \code
807  * AST_VECTOR(, char *) vector_1;
808  * AST_VECTOR(, char *) *vector_2;
809  *
810  * vector_2 = AST_VECTOR_CALLBACK_MULTIPLE(&vector_1, callback);
811  * \endcode
812  *
813  * This will work because you're using the type of the first
814  * to declare the second:
815  *
816  * \code
817  * AST_VECTOR(mytype, char *) vector_1;
818  * struct mytype *vector_2 = NULL;
819  *
820  * vector_2 = AST_VECTOR_CALLBACK_MULTIPLE(&vector_1, callback);
821  * \endcode
822  *
823  * This will also work because you're declaring both vector_1 and
824  * vector_2 from the same definition.
825  *
826  * \code
827  * AST_VECTOR(, char *) vector_1, *vector_2 = NULL;
828  *
829  * vector_2 = AST_VECTOR_CALLBACK_MULTIPLE(&vector_1, callback);
830  * \endcode
831  */
832 #define AST_VECTOR_CALLBACK_MULTIPLE(vec, callback, ...) ({ \
833  size_t idx; \
834  typeof((vec)) new_vec; \
835  do { \
836  new_vec = ast_malloc(sizeof(*new_vec)); \
837  if (!new_vec) { \
838  break; \
839  } \
840  if (AST_VECTOR_INIT(new_vec, AST_VECTOR_SIZE((vec))) != 0) { \
841  ast_free(new_vec); \
842  new_vec = NULL; \
843  break; \
844  } \
845  for (idx = 0; idx < (vec)->current; idx++) { \
846  int rc = callback((vec)->elems[idx], ##__VA_ARGS__); \
847  if (rc & CMP_MATCH) { \
848  AST_VECTOR_APPEND(new_vec, (vec)->elems[idx]); \
849  } \
850  if (rc & CMP_STOP) { \
851  break; \
852  }\
853  } \
854  } while(0); \
855  new_vec; \
856 })
857 
858 /*!
859  * \brief Execute a callback on every element in a vector disregarding callback return
860  *
861  * \param vec Vector to operate on.
862  * \param callback A callback that takes at least 1 argument (the element)
863  * plus number of optional arguments
864  */
865 #define AST_VECTOR_CALLBACK_VOID(vec, callback, ...) ({ \
866  size_t idx; \
867  for (idx = 0; idx < (vec)->current; idx++) { \
868  callback((vec)->elems[idx], ##__VA_ARGS__); \
869  } \
870 })
871 
872 /*!
873  * \brief Obtain read lock on vector
874  *
875  * \param vec Vector to operate on.
876  *
877  * \return 0 if success
878  * \return Non-zero if error
879  */
880 #define AST_VECTOR_RW_RDLOCK(vec) ast_rwlock_rdlock(&(vec)->lock)
881 
882 /*!
883  * \brief Obtain write lock on vector
884  *
885  * \param vec Vector to operate on.
886  *
887  * \return 0 if success
888  * \return Non-zero if error
889  */
890 #define AST_VECTOR_RW_WRLOCK(vec) ast_rwlock_wrlock(&(vec)->lock)
891 
892 /*!
893  * \brief Unlock vector
894  *
895  * \param vec Vector to operate on.
896  *
897  * \return 0 if success
898  * \return Non-zero if error
899  */
900 #define AST_VECTOR_RW_UNLOCK(vec) ast_rwlock_unlock(&(vec)->lock)
901 
902 /*!
903  * \brief Try to obtain read lock on vector failing immediately if unable
904  *
905  * \param vec Vector to operate on.
906  *
907  * \return 0 if success
908  * \return Non-zero if error
909  */
910 #define AST_VECTOR_RW_RDLOCK_TRY(vec) ast_rwlock_tryrdlock(&(vec)->lock)
911 
912 /*!
913  * \brief Try to obtain write lock on vector failing immediately if unable
914  *
915  * \param vec Vector to operate on.
916  *
917  * \return 0 if success
918  * \return Non-zero if error
919  */
920 #define AST_VECTOR_RW_WRLOCK_TRY(vec) ast_rwlock_trywrlock(&(vec)->lock)
921 
922 /*!
923  * \brief Try to obtain read lock on vector failing after timeout if unable
924  *
925  * \param vec Vector to operate on.
926  *
927  * \return 0 if success
928  * \return Non-zero if error
929  */
930 #define AST_VECTOR_RW_RDLOCK_TIMED(vec, timespec) ast_rwlock_timedrdlock(&(vec)->lock, timespec)
931 
932 /*!
933  * \brief Try to obtain write lock on vector failing after timeout if unable
934  *
935  * \param vec Vector to operate on.
936  *
937  * \return 0 if success
938  * \return Non-zero if error
939  */
940 #define AST_VECTOR_RW_WRLOCK_TIMED(vec, timespec) ast_rwlock_timedwrlock(&(vec)->lock, timespec)
941 
942 #endif /* _ASTERISK_VECTOR_H */
Asterisk locking-related definitions:
static int input(yyscan_t yyscanner)
Definition: ast_expr2f.c:1584
#define AST_VECTOR(name, type)
Define a vector structure.
Definition: vector.h:44
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:393
ast_vector_string_split_flags
Definition: vector.h:59