Asterisk - The Open Source Telephony Project GIT-master-5467495
Loading...
Searching...
No Matches
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 Binary search a sorted vector
413 *
414 * \param vec Sorted vector to search.
415 * \param key The key to search for.
416 * \param cmp A bsearch compatible compare function.
417 *
418 * \return a pointer to the found element, or NULL if not found.
419 *
420 * \warning This macro requires the vector to have been sorted.
421 */
422#define AST_VECTOR_BSEARCH(vec, key, cmp) ({ \
423 typeof(key) __key = (key); \
424 bsearch(&__key, (vec)->elems, (vec)->current, \
425 sizeof(typeof((vec)->elems[0])), cmp); \
426})
427
428/*!
429 * \brief Remove an element from a 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 * \param preserve_ordered Preserve the vector order.
437 *
438 * \return The element that was removed.
439 */
440#define AST_VECTOR_REMOVE(vec, idx, preserve_ordered) ({ \
441 typeof((vec)->elems[0]) res; \
442 size_t __idx = (idx); \
443 ast_assert(__idx < (vec)->current); \
444 res = (vec)->elems[__idx]; \
445 if ((preserve_ordered)) { \
446 size_t __move; \
447 __move = ((vec)->current - (__idx) - 1) * sizeof(typeof((vec)->elems[0])); \
448 memmove(&(vec)->elems[__idx], &(vec)->elems[__idx + 1], __move); \
449 (vec)->current--; \
450 } else { \
451 (vec)->elems[__idx] = (vec)->elems[--(vec)->current]; \
452 }; \
453 res; \
454})
455
456/*!
457 * \brief Remove an element from an unordered vector by index.
458 *
459 * Note that elements in the vector may be reordered, so that the remove can
460 * happen in constant time.
461 *
462 * \param vec Vector to remove from.
463 * \param idx Index of the element to remove.
464 * \return The element that was removed.
465 */
466#define AST_VECTOR_REMOVE_UNORDERED(vec, idx) \
467 AST_VECTOR_REMOVE(vec, idx, 0)
468
469/*!
470 * \brief Remove an element from a vector by index while maintaining order.
471 *
472 * \param vec Vector to remove from.
473 * \param idx Index of the element to remove.
474 * \return The element that was removed.
475 */
476#define AST_VECTOR_REMOVE_ORDERED(vec, idx) \
477 AST_VECTOR_REMOVE(vec, idx, 1)
478
479/*!
480 * \brief Remove all elements from a vector that matches the given comparison
481 *
482 * \param vec Vector to remove from.
483 * \param value Value to pass into comparator.
484 * \param cmp Comparator function/macros (called as \c cmp(elem, value))
485 * \param cleanup How to cleanup a removed element macro/function.
486 *
487 * \return the number of deleted elements.
488 */
489#define AST_VECTOR_REMOVE_ALL_CMP_UNORDERED(vec, value, cmp, cleanup) ({ \
490 int count = 0; \
491 size_t idx; \
492 typeof(value) __value = (value); \
493 for (idx = 0; idx < (vec)->current; ) { \
494 if (cmp((vec)->elems[idx], __value)) { \
495 cleanup((vec)->elems[idx]); \
496 AST_VECTOR_REMOVE_UNORDERED((vec), idx); \
497 ++count; \
498 } else { \
499 ++idx; \
500 } \
501 } \
502 count; \
503})
504
505/*!
506 * \brief Remove an element from a vector that matches the given comparison
507 *
508 * \param vec Vector to remove from.
509 * \param value Value to pass into comparator.
510 * \param cmp Comparator function/macros (called as \c cmp(elem, value))
511 * \param cleanup How to cleanup a removed element macro/function.
512 *
513 * \retval 0 if element was removed.
514 * \retval Non-zero if element was not in the vector.
515 */
516#define AST_VECTOR_REMOVE_CMP_UNORDERED(vec, value, cmp, cleanup) ({ \
517 int res = -1; \
518 size_t idx; \
519 typeof(value) __value = (value); \
520 for (idx = 0; idx < (vec)->current; ++idx) { \
521 if (cmp((vec)->elems[idx], __value)) { \
522 cleanup((vec)->elems[idx]); \
523 AST_VECTOR_REMOVE_UNORDERED((vec), idx); \
524 res = 0; \
525 break; \
526 } \
527 } \
528 res; \
529})
530
531/*!
532 * \brief Remove all elements from a vector that matches the given comparison while maintaining order
533 *
534 * \param vec Vector to remove from.
535 * \param value Value to pass into comparator.
536 * \param cmp Comparator function/macros (called as \c cmp(elem, value))
537 * \param cleanup How to cleanup a removed element macro/function.
538 *
539 * \return the number of deleted elements.
540 */
541#define AST_VECTOR_REMOVE_ALL_CMP_ORDERED(vec, value, cmp, cleanup) ({ \
542 int count = 0; \
543 size_t idx; \
544 typeof(value) __value = (value); \
545 for (idx = 0; idx < (vec)->current; ) { \
546 if (cmp((vec)->elems[idx], __value)) { \
547 cleanup((vec)->elems[idx]); \
548 AST_VECTOR_REMOVE_ORDERED((vec), idx); \
549 ++count; \
550 } else { \
551 ++idx; \
552 } \
553 } \
554 count; \
555})
556
557/*!
558 * \brief Remove an element from a vector that matches the given comparison while maintaining order
559 *
560 * \param vec Vector to remove from.
561 * \param value Value to pass into comparator.
562 * \param cmp Comparator function/macros (called as \c cmp(elem, value))
563 * \param cleanup How to cleanup a removed element macro/function.
564 *
565 * \retval 0 if element was removed.
566 * \retval Non-zero if element was not in the vector.
567 */
568#define AST_VECTOR_REMOVE_CMP_ORDERED(vec, value, cmp, cleanup) ({ \
569 int res = -1; \
570 size_t idx; \
571 typeof(value) __value = (value); \
572 for (idx = 0; idx < (vec)->current; ++idx) { \
573 if (cmp((vec)->elems[idx], __value)) { \
574 cleanup((vec)->elems[idx]); \
575 AST_VECTOR_REMOVE_ORDERED((vec), idx); \
576 res = 0; \
577 break; \
578 } \
579 } \
580 res; \
581})
582
583/*!
584 * \brief Default comparator for AST_VECTOR_REMOVE_ELEM_UNORDERED()
585 *
586 * \param elem Element to compare against
587 * \param value Value to compare with the vector element.
588 *
589 * \retval 0 if element does not match.
590 * \retval Non-zero if element matches.
591 */
592#define AST_VECTOR_ELEM_DEFAULT_CMP(elem, value) ((elem) == (value))
593
594/*!
595 * \brief Vector element cleanup that does nothing.
596 *
597 * \param elem Element to cleanup
598 */
599#define AST_VECTOR_ELEM_CLEANUP_NOOP(elem)
600
601/*!
602 * \brief Remove an element from a vector.
603 *
604 * \param vec Vector to remove from.
605 * \param elem Element to remove
606 * \param cleanup How to cleanup a removed element macro/function.
607 *
608 * \retval 0 if element was removed.
609 * \retval Non-zero if element was not in the vector.
610 */
611#define AST_VECTOR_REMOVE_ELEM_UNORDERED(vec, elem, cleanup) ({ \
612 AST_VECTOR_REMOVE_CMP_UNORDERED((vec), (elem), \
613 AST_VECTOR_ELEM_DEFAULT_CMP, cleanup); \
614})
615
616/*!
617 * \brief Remove an element from a vector while maintaining order.
618 *
619 * \param vec Vector to remove from.
620 * \param elem Element to remove
621 * \param cleanup How to cleanup a removed element macro/function.
622 *
623 * \retval 0 if element was removed.
624 * \retval Non-zero if element was not in the vector.
625 */
626#define AST_VECTOR_REMOVE_ELEM_ORDERED(vec, elem, cleanup) ({ \
627 AST_VECTOR_REMOVE_CMP_ORDERED((vec), (elem), \
628 AST_VECTOR_ELEM_DEFAULT_CMP, cleanup); \
629})
630
631/*!
632 * \brief Get the number of elements in a vector.
633 *
634 * \param vec Vector to query.
635 * \return Number of elements in the vector.
636 */
637#define AST_VECTOR_SIZE(vec) (vec)->current
638
639/*!
640 * \brief Get the maximum number of elements the vector can currently hold.
641 *
642 * \param vec Vector to query.
643 * \return Maximum number of elements the vector can currently hold.
644 */
645#define AST_VECTOR_MAX_SIZE(vec) (vec)->max
646
647/*!
648 * \brief Reset vector.
649 *
650 * \param vec Vector to reset.
651 * \param cleanup A cleanup callback or AST_VECTOR_ELEM_CLEANUP_NOOP.
652 */
653#define AST_VECTOR_RESET(vec, cleanup) ({ \
654 AST_VECTOR_CALLBACK_VOID(vec, cleanup); \
655 (vec)->current = 0; \
656})
657
658/*!
659 * \brief Resize a vector so that its capacity is the same as its size.
660 *
661 * \param vec Vector to compact.
662 *
663 * \retval 0 on success.
664 * \retval Non-zero on failure.
665 */
666#define AST_VECTOR_COMPACT(vec) ({ \
667 int res = 0; \
668 do { \
669 size_t new_max = (vec)->current; \
670 if (new_max == 0) { \
671 ast_free((vec)->elems); \
672 (vec)->elems = NULL; \
673 (vec)->max = 0; \
674 } else if ((vec)->max > new_max) { \
675 typeof((vec)->elems) new_elems = ast_realloc( \
676 (vec)->elems, \
677 new_max * sizeof(*new_elems)); \
678 if (new_elems) { \
679 (vec)->elems = new_elems; \
680 (vec)->max = new_max; \
681 } else { \
682 res = -1; \
683 break; \
684 } \
685 } \
686 } while(0); \
687 res; \
688})
689
690/*!
691 * \brief Get an address of element in a vector.
692 *
693 * \param vec Vector to query.
694 * \param idx Index of the element to get address of.
695 */
696#define AST_VECTOR_GET_ADDR(vec, idx) ({ \
697 size_t __idx = (idx); \
698 ast_assert(__idx < (vec)->current); \
699 &(vec)->elems[__idx]; \
700})
701
702/*!
703 * \brief Get an element from a vector.
704 *
705 * \param vec Vector to query.
706 * \param idx Index of the element to get.
707 */
708#define AST_VECTOR_GET(vec, idx) ({ \
709 size_t __idx = (idx); \
710 ast_assert(__idx < (vec)->current); \
711 (vec)->elems[__idx]; \
712})
713
714/*!
715 * \brief Get the nth index from a vector that matches the given comparison
716 *
717 * \param vec Vector to get from.
718 * \param nth The nth index to find
719 * \param value Value to pass into comparator.
720 * \param cmp Comparator function/macros (called as \c cmp(elem, value))
721 *
722 * \return a pointer to the element that was found or NULL
723 */
724#define AST_VECTOR_GET_INDEX_NTH(vec, nth, value, cmp) ({ \
725 int res = -1; \
726 size_t idx; \
727 typeof(nth) __nth = (nth); \
728 typeof(value) __value = (value); \
729 for (idx = 0; idx < (vec)->current; ++idx) { \
730 if (cmp((vec)->elems[idx], __value) && !(--__nth)) { \
731 res = (int)idx; \
732 break; \
733 } \
734 } \
735 res; \
736})
737
738/*!
739 * \brief Get the 1st index from a vector that matches the given comparison
740 *
741 * \param vec Vector to get from.
742 * \param value Value to pass into comparator.
743 * \param cmp Comparator function/macros (called as \c cmp(elem, value))
744 *
745 * \return a pointer to the element that was found or NULL
746 */
747#define AST_VECTOR_GET_INDEX(vec, value, cmp) \
748 AST_VECTOR_GET_INDEX_NTH(vec, 1, value, cmp)
749
750/*!
751 * \brief Get an element from a vector that matches the given comparison
752 *
753 * \param vec Vector to get from.
754 * \param value Value to pass into comparator.
755 * \param cmp Comparator function/macros (called as \c cmp(elem, value))
756 *
757 * \return a pointer to the element that was found or NULL
758 */
759#define AST_VECTOR_GET_CMP(vec, value, cmp) ({ \
760 void *res = NULL; \
761 size_t idx; \
762 typeof(value) __value = (value); \
763 for (idx = 0; idx < (vec)->current; ++idx) { \
764 if (cmp((vec)->elems[idx], __value)) { \
765 res = &(vec)->elems[idx]; \
766 break; \
767 } \
768 } \
769 res; \
770})
771
772/*!
773 * \brief Default callback for AST_VECTOR_CALLBACK()
774 *
775 * \param element Element to compare against
776 *
777 * \retval CMP_MATCH always.
778 */
779#define AST_VECTOR_MATCH_ALL(element) (CMP_MATCH)
780
781
782/*!
783 * \brief Execute a callback on every element in a vector returning the first matched
784 *
785 * \param vec Vector to operate on.
786 * \param callback A callback that takes at least 1 argument (the element)
787 * plus number of optional arguments
788 * \param default_value A default value to return if no elements matched
789 *
790 * \return the first element matched before CMP_STOP was returned
791 * or the end of the vector was reached. Otherwise, default_value
792 */
793#define AST_VECTOR_CALLBACK(vec, callback, default_value, ...) ({ \
794 size_t idx; \
795 typeof((vec)->elems[0]) res = default_value; \
796 for (idx = 0; idx < (vec)->current; idx++) { \
797 int rc = callback((vec)->elems[idx], ##__VA_ARGS__); \
798 if (rc & CMP_MATCH) { \
799 res = (vec)->elems[idx]; \
800 break; \
801 }\
802 if (rc & CMP_STOP) { \
803 break; \
804 }\
805 } \
806 res; \
807})
808
809/*!
810 * \brief Execute a callback on every element in a vector returning the matching
811 * elements in a new vector
812 *
813 * This macro basically provides a filtered clone.
814 *
815 * \param vec Vector to operate on.
816 * \param callback A callback that takes at least 1 argument (the element)
817 * plus number of optional arguments
818 *
819 * \return a vector containing the elements matched before CMP_STOP was returned
820 * or the end of the vector was reached. The vector may be empty and could be NULL
821 * if there was not enough memory to allocate it's control structure.
822 *
823 * \warning The returned vector must have AST_VECTOR_PTR_FREE()
824 * called on it after you've finished with it.
825 *
826 * \note The type of the returned vector must be traceable to the original vector.
827 *
828 * The following will result in "error: assignment from incompatible pointer type"
829 * because these declare 2 different structures.
830 *
831 * \code
832 * AST_VECTOR(, char *) vector_1;
833 * AST_VECTOR(, char *) *vector_2;
834 *
835 * vector_2 = AST_VECTOR_CALLBACK_MULTIPLE(&vector_1, callback);
836 * \endcode
837 *
838 * This will work because you're using the type of the first
839 * to declare the second:
840 *
841 * \code
842 * AST_VECTOR(mytype, char *) vector_1;
843 * struct mytype *vector_2 = NULL;
844 *
845 * vector_2 = AST_VECTOR_CALLBACK_MULTIPLE(&vector_1, callback);
846 * \endcode
847 *
848 * This will also work because you're declaring both vector_1 and
849 * vector_2 from the same definition.
850 *
851 * \code
852 * AST_VECTOR(, char *) vector_1, *vector_2 = NULL;
853 *
854 * vector_2 = AST_VECTOR_CALLBACK_MULTIPLE(&vector_1, callback);
855 * \endcode
856 */
857#define AST_VECTOR_CALLBACK_MULTIPLE(vec, callback, ...) ({ \
858 size_t idx; \
859 typeof((vec)) new_vec; \
860 do { \
861 new_vec = ast_malloc(sizeof(*new_vec)); \
862 if (!new_vec) { \
863 break; \
864 } \
865 if (AST_VECTOR_INIT(new_vec, AST_VECTOR_SIZE((vec))) != 0) { \
866 ast_free(new_vec); \
867 new_vec = NULL; \
868 break; \
869 } \
870 for (idx = 0; idx < (vec)->current; idx++) { \
871 int rc = callback((vec)->elems[idx], ##__VA_ARGS__); \
872 if (rc & CMP_MATCH) { \
873 AST_VECTOR_APPEND(new_vec, (vec)->elems[idx]); \
874 } \
875 if (rc & CMP_STOP) { \
876 break; \
877 }\
878 } \
879 } while(0); \
880 new_vec; \
881})
882
883/*!
884 * \brief Execute a callback on every element in a vector disregarding callback return
885 *
886 * \param vec Vector to operate on.
887 * \param callback A callback that takes at least 1 argument (the element)
888 * plus number of optional arguments
889 */
890#define AST_VECTOR_CALLBACK_VOID(vec, callback, ...) ({ \
891 size_t idx; \
892 for (idx = 0; idx < (vec)->current; idx++) { \
893 callback((vec)->elems[idx], ##__VA_ARGS__); \
894 } \
895})
896
897/*!
898 * \brief Obtain read lock on vector
899 *
900 * \param vec Vector to operate on.
901 *
902 * \retval 0 if success
903 * \retval Non-zero if error
904 */
905#define AST_VECTOR_RW_RDLOCK(vec) ast_rwlock_rdlock(&(vec)->lock)
906
907/*!
908 * \brief Obtain write lock on vector
909 *
910 * \param vec Vector to operate on.
911 *
912 * \retval 0 if success
913 * \retval Non-zero if error
914 */
915#define AST_VECTOR_RW_WRLOCK(vec) ast_rwlock_wrlock(&(vec)->lock)
916
917/*!
918 * \brief Unlock vector
919 *
920 * \param vec Vector to operate on.
921 *
922 * \retval 0 if success
923 * \retval Non-zero if error
924 */
925#define AST_VECTOR_RW_UNLOCK(vec) ast_rwlock_unlock(&(vec)->lock)
926
927/*!
928 * \brief Try to obtain read lock on vector failing immediately if unable
929 *
930 * \param vec Vector to operate on.
931 *
932 * \retval 0 if success
933 * \retval Non-zero if error
934 */
935#define AST_VECTOR_RW_RDLOCK_TRY(vec) ast_rwlock_tryrdlock(&(vec)->lock)
936
937/*!
938 * \brief Try to obtain write lock on vector failing immediately if unable
939 *
940 * \param vec Vector to operate on.
941 *
942 * \retval 0 if success
943 * \retval Non-zero if error
944 */
945#define AST_VECTOR_RW_WRLOCK_TRY(vec) ast_rwlock_trywrlock(&(vec)->lock)
946
947/*!
948 * \brief Try to obtain read lock on vector failing after timeout if unable
949 *
950 * \param vec Vector to operate on.
951 * \param timespec
952 *
953 * \retval 0 if success
954 * \retval Non-zero if error
955 */
956#define AST_VECTOR_RW_RDLOCK_TIMED(vec, timespec) ast_rwlock_timedrdlock(&(vec)->lock, timespec)
957
958/*!
959 * \brief Try to obtain write lock on vector failing after timeout if unable
960 *
961 * \param vec Vector to operate on.
962 * \param timespec
963 *
964 * \retval 0 if success
965 * \retval Non-zero if error
966 */
967#define AST_VECTOR_RW_WRLOCK_TIMED(vec, timespec) ast_rwlock_timedwrlock(&(vec)->lock, timespec)
968
969#endif /* _ASTERISK_VECTOR_H */
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