1 /* Copyright (c) 2003-2004, Roger Dingledine 2 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. 3 * Copyright (c) 2007-2021, The Tor Project, Inc. */ 4 /* See LICENSE for licensing information */ 5 6 /** 7 * \file smartlist_foreach.h 8 * \brief Macros for iterating over the elements of a smartlist_t. 9 **/ 10 11 #ifndef TOR_SMARTLIST_FOREACH_H 12 #define TOR_SMARTLIST_FOREACH_H 13 14 /** Iterate over the items in a smartlist <b>sl</b>, in order. For each item, 15 * assign it to a new local variable of type <b>type</b> named <b>var</b>, and 16 * execute the statements inside the loop body. Inside the loop, the loop 17 * index can be accessed as <b>var</b>_sl_idx and the length of the list can 18 * be accessed as <b>var</b>_sl_len. 19 * 20 * NOTE: Do not change the length of the list while the loop is in progress, 21 * unless you adjust the _sl_len variable correspondingly. See second example 22 * below. 23 * 24 * Example use: 25 * <pre> 26 * smartlist_t *list = smartlist_split("A:B:C", ":", 0, 0); 27 * SMARTLIST_FOREACH_BEGIN(list, char *, cp) { 28 * printf("%d: %s\n", cp_sl_idx, cp); 29 * tor_free(cp); 30 * } SMARTLIST_FOREACH_END(cp); 31 * smartlist_free(list); 32 * </pre> 33 * 34 * Example use (advanced): 35 * <pre> 36 * SMARTLIST_FOREACH_BEGIN(list, char *, cp) { 37 * if (!strcmp(cp, "junk")) { 38 * tor_free(cp); 39 * SMARTLIST_DEL_CURRENT(list, cp); 40 * } 41 * } SMARTLIST_FOREACH_END(cp); 42 * </pre> 43 */ 44 /* Note: these macros use token pasting, and reach into smartlist internals. 45 * This can make them a little daunting. Here's the approximate unpacking of 46 * the above examples, for entertainment value: 47 * 48 * <pre> 49 * smartlist_t *list = smartlist_split("A:B:C", ":", 0, 0); 50 * { 51 * int cp_sl_idx, cp_sl_len = smartlist_len(list); 52 * char *cp; 53 * for (cp_sl_idx = 0; cp_sl_idx < cp_sl_len; ++cp_sl_idx) { 54 * cp = smartlist_get(list, cp_sl_idx); 55 * printf("%d: %s\n", cp_sl_idx, cp); 56 * tor_free(cp); 57 * } 58 * } 59 * smartlist_free(list); 60 * </pre> 61 * 62 * <pre> 63 * { 64 * int cp_sl_idx, cp_sl_len = smartlist_len(list); 65 * char *cp; 66 * for (cp_sl_idx = 0; cp_sl_idx < cp_sl_len; ++cp_sl_idx) { 67 * cp = smartlist_get(list, cp_sl_idx); 68 * if (!strcmp(cp, "junk")) { 69 * tor_free(cp); 70 * smartlist_del(list, cp_sl_idx); 71 * --cp_sl_idx; 72 * --cp_sl_len; 73 * } 74 * } 75 * } 76 * </pre> 77 */ 78 #define SMARTLIST_FOREACH_BEGIN(sl, type, var) \ 79 STMT_BEGIN \ 80 int var ## _sl_idx, var ## _sl_len=(sl)->num_used; \ 81 type var; \ 82 for (var ## _sl_idx = 0; var ## _sl_idx < var ## _sl_len; \ 83 ++var ## _sl_idx) { \ 84 var = (sl)->list[var ## _sl_idx]; 85 86 /** Iterates over the items in smartlist <b>sl</b> in reverse order, similar to 87 * SMARTLIST_FOREACH_BEGIN 88 * 89 * NOTE: This macro is incompatible with SMARTLIST_DEL_CURRENT. 90 */ 91 #define SMARTLIST_FOREACH_REVERSE_BEGIN(sl, type, var) \ 92 STMT_BEGIN \ 93 int var ## _sl_idx, var ## _sl_len=(sl)->num_used; \ 94 type var; \ 95 for (var ## _sl_idx = var ## _sl_len-1; var ## _sl_idx >= 0; \ 96 --var ## _sl_idx) { \ 97 var = (sl)->list[var ## _sl_idx]; 98 99 #define SMARTLIST_FOREACH_END(var) \ 100 var = NULL; \ 101 (void) var ## _sl_idx; \ 102 } STMT_END 103 104 /** 105 * An alias for SMARTLIST_FOREACH_BEGIN and SMARTLIST_FOREACH_END, using 106 * <b>cmd</b> as the loop body. This wrapper is here for convenience with 107 * very short loops. 108 * 109 * By convention, we do not use this for loops which nest, or for loops over 110 * 10 lines or so. Use SMARTLIST_FOREACH_{BEGIN,END} for those. 111 */ 112 #define SMARTLIST_FOREACH(sl, type, var, cmd) \ 113 SMARTLIST_FOREACH_BEGIN(sl,type,var) { \ 114 cmd; \ 115 } SMARTLIST_FOREACH_END(var) 116 117 /** Helper: While in a SMARTLIST_FOREACH loop over the list <b>sl</b> indexed 118 * with the variable <b>var</b>, remove the current element in a way that 119 * won't confuse the loop. */ 120 #define SMARTLIST_DEL_CURRENT(sl, var) \ 121 STMT_BEGIN \ 122 smartlist_del(sl, var ## _sl_idx); \ 123 --var ## _sl_idx; \ 124 --var ## _sl_len; \ 125 STMT_END 126 127 /** Helper: While in a SMARTLIST_FOREACH loop over the list <b>sl</b> indexed 128 * with the variable <b>var</b>, remove the current element in a way that 129 * won't confuse the loop. */ 130 #define SMARTLIST_DEL_CURRENT_KEEPORDER(sl, var) \ 131 STMT_BEGIN \ 132 smartlist_del_keeporder(sl, var ## _sl_idx); \ 133 --var ## _sl_idx; \ 134 --var ## _sl_len; \ 135 STMT_END 136 137 /** Helper: While in a SMARTLIST_FOREACH loop over the list <b>sl</b> indexed 138 * with the variable <b>var</b>, replace the current element with <b>val</b>. 139 * Does not deallocate the current value of <b>var</b>. 140 */ 141 #define SMARTLIST_REPLACE_CURRENT(sl, var, val) \ 142 STMT_BEGIN \ 143 smartlist_set(sl, var ## _sl_idx, val); \ 144 STMT_END 145 146 #endif /* !defined(TOR_SMARTLIST_FOREACH_H) */ 147