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