diff options
author | Nick Mathewson <nickm@torproject.org> | 2008-04-07 16:28:34 +0000 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2008-04-07 16:28:34 +0000 |
commit | 2d68487e7fda553ce1466047aec954936688083b (patch) | |
tree | aaec7e96548c0c848a33b5b061384adfb630b5ec /src/common/container.h | |
parent | 85db675911d1b4bbba755266ebaa33404c40e5de (diff) | |
download | tor-2d68487e7fda553ce1466047aec954936688083b.tar.gz tor-2d68487e7fda553ce1466047aec954936688083b.zip |
r19229@catbus: nickm | 2008-04-07 12:28:22 -0400
Add a new SMARTLIST_FOREACH_JOIN macro to iterate through two sorted lists in lockstep. This happens at least 3 times in the code so far, and is likely to happen more in the future. Previous attempts to do so proved touchy, tricky, and error-prone: now, we only need to get it right in one place.
svn:r14309
Diffstat (limited to 'src/common/container.h')
-rw-r--r-- | src/common/container.h | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/src/common/container.h b/src/common/container.h index 6daef6e833..866cb1b8a9 100644 --- a/src/common/container.h +++ b/src/common/container.h @@ -215,6 +215,80 @@ char *smartlist_join_strings2(smartlist_t *sl, const char *join, --var ## _sl_len; \ STMT_END +/* Helper: Given two lists of items, possibly of different types, such that + * both lists are sorted on some common field (as determened by a comparison + * expression <b>cmpexpr</b>), and such that one list (<b>sl1</b>) has no + * duplicates on the common field, loop through the lists in lockstep, and + * execute <b>unmatched_var2</b> on items in var2 that do not appear in + * var1. + * + * WARNING: It isn't safe to add remove elements from either list while the + * loop is in progress. + * + * Example use: + * SMARTLIST_FOREACH_JOIN(routerstatus_list, routerstatus_t *, rs, + * routerinfo_list, routerinfo_t *, ri, + * memcmp(rs->identity_digest, ri->identity_digest, 20), + * log_info(LD_GENERAL,"No match for %s", ri->nickname)) { + * log_info(LD_GENERAL, "%s matches routerstatus %p", ri->nickname, rs); + * } SMARTLIST_FOREACH_JOIN_END(rs, ri); + **/ +/* The example above unpacks (approximately) to: + * int rs_sl_idx = 0, rs_sl_len = smartlist_len(routerstatus_list); + * int ri_sl_idx, ri_sl_len = smartlist_len(routerinfo_list); + * int rs_ri_cmp; + * routerstatus_t *rs; + * routerinfo_t *ri; + * for (; ri_sl_idx < ri_sl_len; ++ri_sl_idx) { + * ri = smartlist_get(routerinfo_list, ri_sl_idx); + * while (rs_sl_idx < rs_sl_len) { + * rs = smartlist_get(routerstatus_list, rs_sl_idx); + * rs_ri_cmp = memcmp(rs->identity_digest, ri->identity_digest, 20); + * if (rs_ri_cmp > 0) { + * break; + * } else if (rs_ri_cmp == 0) { + * goto matched_ri; + * } else { + * ++rs_sl_idx; + * } + * } + * log_info(LD_GENERAL,"No match for %s", ri->nickname); + * continue; + * matched_ri: { + * log_info(LD_GENERAL,"%s matches with routerstatus %p",ri->nickname,rs); + * } + * } + */ +#define SMARTLIST_FOREACH_JOIN(sl1, type1, var1, sl2, type2, var2, \ + cmpexpr, unmatched_var2) \ + STMT_BEGIN \ + int var1 ## _sl_idx = 0, var1 ## _sl_len=(sl1)->num_used; \ + int var2 ## _sl_idx = 0, var2 ## _sl_len=(sl2)->num_used; \ + int var1 ## _ ## var2 ## _cmp; \ + type1 var1; \ + type2 var2; \ + for (; var2##_sl_idx < var2##_sl_len; ++var2##_sl_idx) { \ + var2 = (sl2)->list[var2##_sl_idx]; \ + while (var1##_sl_idx < var1##_sl_len) { \ + var1 = (sl1)->list[var1##_sl_idx]; \ + var1##_##var2##_cmp = (cmpexpr); \ + if (var1##_##var2##_cmp > 0) { \ + break; \ + } else if (var1##_##var2##_cmp == 0) { \ + goto matched_##var2; \ + } else { \ + ++var1##_sl_idx; \ + } \ + } \ + /* Ran out of v1, or no match for var2. */ \ + unmatched_var2; \ + continue; \ + matched_##var2: ; \ + +#define SMARTLIST_FOREACH_JOIN_END(var1, var2) \ + } \ + STMT_END + #define DECLARE_MAP_FNS(maptype, keytype, prefix) \ typedef struct maptype maptype; \ typedef struct prefix##entry_t *prefix##iter_t; \ |