foreach.h 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. #ifndef CCAN_FOREACH_H
  2. #define CCAN_FOREACH_H
  3. #include "config.h"
  4. #include <stddef.h>
  5. #include <assert.h>
  6. #include <stdbool.h>
  7. #if HAVE_COMPOUND_LITERALS
  8. #if HAVE_FOR_LOOP_DECLARATION
  9. /**
  10. * foreach_int - iterate over a fixed series of integers
  11. * @i: the int-compatible iteration variable
  12. * @val: one or more integer-compatible values
  13. *
  14. * This is a convenient wrapper function for setting a variable to one or
  15. * more explicit values in turn. continue and break work as expected.
  16. *
  17. * Example:
  18. * int i;
  19. * foreach_int(i, 0, -1, 100, 0, -99) {
  20. * printf("i is %i\n", i);
  21. * }
  22. */
  23. #define foreach_int(i, val, ...) \
  24. for (unsigned _foreach_i = ((i) = val, 0); \
  25. _foreach_i < sizeof((int[]) { val, __VA_ARGS__ })/sizeof(val); \
  26. (i) = (int[]) { val, __VA_ARGS__, 0 }[++_foreach_i])
  27. /**
  28. * foreach_ptr - iterate over a non-NULL series of pointers
  29. * @i: the pointer iteration variable
  30. * @val: one or more compatible pointer values
  31. *
  32. * This is a convenient wrapper function for setting a variable to one
  33. * or more explicit values in turn. None of the values can be NULL;
  34. * that is the termination condition (ie. @i will be NULL on
  35. * completion). continue and break work as expected.
  36. *
  37. * Example:
  38. * const char *p;
  39. * foreach_ptr(p, "Hello", "world") {
  40. * printf("p is %s\n", p);
  41. * }
  42. */
  43. #define foreach_ptr(i, val, ...) \
  44. for (unsigned _foreach_i = (unsigned long)((i) = (val), 0); \
  45. (i); \
  46. (i) = ((FOREACH_TYPEOF(val)[]){(val), __VA_ARGS__, NULL}) \
  47. [++_foreach_i], \
  48. _foreach_no_nullval(_foreach_i, i, \
  49. ((void *[]){ val, __VA_ARGS__})))
  50. #else /* !HAVE_FOR_LOOP_DECLARATION */
  51. /* GCC in C89 mode still has compound literals, but no for-declarations */
  52. #define foreach_int(i, val, ...) \
  53. for ((i) = (val), _foreach_iter_init(&(i)); \
  54. _foreach_iter(&(i)) < sizeof((int[]) { (val), __VA_ARGS__ }) \
  55. / sizeof(int); \
  56. (i) = (int[]) { (val), __VA_ARGS__, 0 }[_foreach_iter_inc(&(i))])
  57. #define foreach_ptr(i, val, ...) \
  58. for ((i) = (val), _foreach_iter_init(&(i)); \
  59. (i); \
  60. (i) = ((FOREACH_TYPEOF(val)[]){ (val), __VA_ARGS__, 0 }) \
  61. [_foreach_iter_inc(&(i))], \
  62. _foreach_no_nullval(_foreach_iter(&(i)), i, \
  63. ((void *[]){ val, __VA_ARGS__})))
  64. void _foreach_iter_init(const void *i);
  65. unsigned int _foreach_iter(const void *i);
  66. unsigned int _foreach_iter_inc(const void *i);
  67. #endif /* !HAVE_FOR_LOOP_DECLARATION */
  68. /* Make sure they don't put NULL values into array! */
  69. #define _foreach_no_nullval(i, p, arr) \
  70. assert((i) >= sizeof(arr)/sizeof(arr[0]) || (p))
  71. #if HAVE_TYPEOF
  72. #define FOREACH_TYPEOF(val) __typeof__(&*(val))
  73. #else
  74. #define FOREACH_TYPEOF(val) void *
  75. #endif
  76. #else /* !HAVE_COMPOUND_LITERALS */
  77. /* No compound literals, but it's still (just) possible. */
  78. #define foreach_int(i, val, ...) \
  79. for (i = _foreach_intval_init(&(i), val, __VA_ARGS__, \
  80. _foreach_term); \
  81. !_foreach_intval_done(&i); \
  82. i = _foreach_intval_next(&(i), val, __VA_ARGS__, \
  83. _foreach_term))
  84. #define foreach_ptr(i, val, ...) \
  85. for (i = _foreach_ptrval_init(&(i), val, __VA_ARGS__, NULL); \
  86. (i); \
  87. i = _foreach_ptrval_next(&(i), val, __VA_ARGS__, NULL))
  88. extern int _foreach_term;
  89. int _foreach_intval_init(const void *i, int val, ...);
  90. bool _foreach_intval_done(const void *i);
  91. int _foreach_intval_next(const void *i, int val, ...);
  92. void *_foreach_ptrval_init(const void *i, const void *val, ...);
  93. void *_foreach_ptrval_next(const void *i, const void *val, ...);
  94. #endif /* !HAVE_COMPOUND_LITERALS */
  95. #endif /* CCAN_FOREACH_H */