Tor 0.4.9.0-alpha-dev
smartlist_foreach.h
Go to the documentation of this file.
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) */