vector.h 24 KB

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