Back to index

tor  0.2.3.19-rc
container.h
Go to the documentation of this file.
00001 /* Copyright (c) 2003-2004, Roger Dingledine
00002  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
00003  * Copyright (c) 2007-2012, The Tor Project, Inc. */
00004 /* See LICENSE for licensing information */
00005 
00006 #ifndef _TOR_CONTAINER_H
00007 #define _TOR_CONTAINER_H
00008 
00009 #include "util.h"
00010 
00017 typedef struct smartlist_t {
00023   void **list;
00024   int num_used;
00025   int capacity;
00027 } smartlist_t;
00028 
00029 smartlist_t *smartlist_new(void);
00030 void smartlist_free(smartlist_t *sl);
00031 void smartlist_clear(smartlist_t *sl);
00032 void smartlist_add(smartlist_t *sl, void *element);
00033 void smartlist_add_all(smartlist_t *sl, const smartlist_t *s2);
00034 void smartlist_remove(smartlist_t *sl, const void *element);
00035 void *smartlist_pop_last(smartlist_t *sl);
00036 void smartlist_reverse(smartlist_t *sl);
00037 void smartlist_string_remove(smartlist_t *sl, const char *element);
00038 int smartlist_isin(const smartlist_t *sl, const void *element);
00039 int smartlist_string_isin(const smartlist_t *sl, const char *element);
00040 int smartlist_string_pos(const smartlist_t *, const char *elt);
00041 int smartlist_string_isin_case(const smartlist_t *sl, const char *element);
00042 int smartlist_string_num_isin(const smartlist_t *sl, int num);
00043 int smartlist_strings_eq(const smartlist_t *sl1, const smartlist_t *sl2);
00044 int smartlist_digest_isin(const smartlist_t *sl, const char *element);
00045 int smartlist_overlap(const smartlist_t *sl1, const smartlist_t *sl2);
00046 void smartlist_intersect(smartlist_t *sl1, const smartlist_t *sl2);
00047 void smartlist_subtract(smartlist_t *sl1, const smartlist_t *sl2);
00048 
00049 /* smartlist_choose() is defined in crypto.[ch] */
00050 #ifdef DEBUG_SMARTLIST
00051 
00053 static INLINE int smartlist_len(const smartlist_t *sl);
00054 static INLINE int smartlist_len(const smartlist_t *sl) {
00055   tor_assert(sl);
00056   return (sl)->num_used;
00057 }
00060 static INLINE void *smartlist_get(const smartlist_t *sl, int idx);
00061 static INLINE void *smartlist_get(const smartlist_t *sl, int idx) {
00062   tor_assert(sl);
00063   tor_assert(idx>=0);
00064   tor_assert(sl->num_used > idx);
00065   return sl->list[idx];
00066 }
00067 static INLINE void smartlist_set(smartlist_t *sl, int idx, void *val) {
00068   tor_assert(sl);
00069   tor_assert(idx>=0);
00070   tor_assert(sl->num_used > idx);
00071   sl->list[idx] = val;
00072 }
00073 #else
00074 #define smartlist_len(sl) ((sl)->num_used)
00075 #define smartlist_get(sl, idx) ((sl)->list[idx])
00076 #define smartlist_set(sl, idx, val) ((sl)->list[idx] = (val))
00077 #endif
00078 
00081 static INLINE void smartlist_swap(smartlist_t *sl, int idx1, int idx2)
00082 {
00083   if (idx1 != idx2) {
00084     void *elt = smartlist_get(sl, idx1);
00085     smartlist_set(sl, idx1, smartlist_get(sl, idx2));
00086     smartlist_set(sl, idx2, elt);
00087   }
00088 }
00089 
00090 void smartlist_del(smartlist_t *sl, int idx);
00091 void smartlist_del_keeporder(smartlist_t *sl, int idx);
00092 void smartlist_insert(smartlist_t *sl, int idx, void *val);
00093 void smartlist_sort(smartlist_t *sl,
00094                     int (*compare)(const void **a, const void **b));
00095 void *smartlist_get_most_frequent(const smartlist_t *sl,
00096                     int (*compare)(const void **a, const void **b));
00097 void smartlist_uniq(smartlist_t *sl,
00098                     int (*compare)(const void **a, const void **b),
00099                     void (*free_fn)(void *elt));
00100 
00101 void smartlist_sort_strings(smartlist_t *sl);
00102 void smartlist_sort_digests(smartlist_t *sl);
00103 void smartlist_sort_digests256(smartlist_t *sl);
00104 
00105 char *smartlist_get_most_frequent_string(smartlist_t *sl);
00106 char *smartlist_get_most_frequent_digest256(smartlist_t *sl);
00107 
00108 void smartlist_uniq_strings(smartlist_t *sl);
00109 void smartlist_uniq_digests(smartlist_t *sl);
00110 void smartlist_uniq_digests256(smartlist_t *sl);
00111 void *smartlist_bsearch(smartlist_t *sl, const void *key,
00112                         int (*compare)(const void *key, const void **member));
00113 int smartlist_bsearch_idx(const smartlist_t *sl, const void *key,
00114                           int (*compare)(const void *key, const void **member),
00115                           int *found_out);
00116 
00117 void smartlist_pqueue_add(smartlist_t *sl,
00118                           int (*compare)(const void *a, const void *b),
00119                           int idx_field_offset,
00120                           void *item);
00121 void *smartlist_pqueue_pop(smartlist_t *sl,
00122                            int (*compare)(const void *a, const void *b),
00123                            int idx_field_offset);
00124 void smartlist_pqueue_remove(smartlist_t *sl,
00125                              int (*compare)(const void *a, const void *b),
00126                              int idx_field_offset,
00127                              void *item);
00128 void smartlist_pqueue_assert_ok(smartlist_t *sl,
00129                                 int (*compare)(const void *a, const void *b),
00130                                 int idx_field_offset);
00131 
00132 #define SPLIT_SKIP_SPACE   0x01
00133 #define SPLIT_IGNORE_BLANK 0x02
00134 #define SPLIT_STRIP_SPACE  0x04
00135 int smartlist_split_string(smartlist_t *sl, const char *str, const char *sep,
00136                            int flags, int max);
00137 char *smartlist_join_strings(smartlist_t *sl, const char *join, int terminate,
00138                              size_t *len_out) ATTR_MALLOC;
00139 char *smartlist_join_strings2(smartlist_t *sl, const char *join,
00140                               size_t join_len, int terminate, size_t *len_out)
00141   ATTR_MALLOC;
00142 
00175 /* Note: these macros use token pasting, and reach into smartlist internals.
00176  * This can make them a little daunting. Here's the approximate unpacking of
00177  * the above examples, for entertainment value:
00178  *
00179  * <pre>
00180  * smartlist_t *list = smartlist_split("A:B:C", ":", 0, 0);
00181  * {
00182  *   int cp_sl_idx, cp_sl_len = smartlist_len(list);
00183  *   char *cp;
00184  *   for (cp_sl_idx = 0; cp_sl_idx < cp_sl_len; ++cp_sl_idx) {
00185  *     cp = smartlist_get(list, cp_sl_idx);
00186  *     printf("%d: %s\n", cp_sl_idx, cp);
00187  *     tor_free(cp);
00188  *   }
00189  * }
00190  * smartlist_free(list);
00191  * </pre>
00192  *
00193  * <pre>
00194  * {
00195  *   int cp_sl_idx, cp_sl_len = smartlist_len(list);
00196  *   char *cp;
00197  *   for (cp_sl_idx = 0; cp_sl_idx < cp_sl_len; ++cp_sl_idx) {
00198  *     cp = smartlist_get(list, cp_sl_idx);
00199  *     if (!strcmp(cp, "junk")) {
00200  *       tor_free(cp);
00201  *       smartlist_del(list, cp_sl_idx);
00202  *       --cp_sl_idx;
00203  *       --cp_sl_len;
00204  *     }
00205  *   }
00206  * }
00207  * </pre>
00208  */
00209 #define SMARTLIST_FOREACH_BEGIN(sl, type, var)  \
00210   STMT_BEGIN                                                    \
00211     int var ## _sl_idx, var ## _sl_len=(sl)->num_used;          \
00212     type var;                                                   \
00213     for (var ## _sl_idx = 0; var ## _sl_idx < var ## _sl_len;   \
00214          ++var ## _sl_idx) {                                    \
00215       var = (sl)->list[var ## _sl_idx];
00216 
00217 #define SMARTLIST_FOREACH_END(var)              \
00218     var = NULL;                                 \
00219   } STMT_END
00220 
00221 #define SMARTLIST_FOREACH(sl, type, var, cmd)                   \
00222   SMARTLIST_FOREACH_BEGIN(sl,type,var) {                        \
00223     cmd;                                                        \
00224   } SMARTLIST_FOREACH_END(var)
00225 
00229 #define SMARTLIST_DEL_CURRENT(sl, var)          \
00230   STMT_BEGIN                                    \
00231     smartlist_del(sl, var ## _sl_idx);          \
00232     --var ## _sl_idx;                           \
00233     --var ## _sl_len;                           \
00234   STMT_END
00235 
00240 #define SMARTLIST_REPLACE_CURRENT(sl, var, val) \
00241   STMT_BEGIN                                    \
00242     smartlist_set(sl, var ## _sl_idx, val);     \
00243   STMT_END
00244 
00245 /* Helper: Given two lists of items, possibly of different types, such that
00246  * both lists are sorted on some common field (as determined by a comparison
00247  * expression <b>cmpexpr</b>), and such that one list (<b>sl1</b>) has no
00248  * duplicates on the common field, loop through the lists in lockstep, and
00249  * execute <b>unmatched_var2</b> on items in var2 that do not appear in
00250  * var1.
00251  *
00252  * WARNING: It isn't safe to add remove elements from either list while the
00253  * loop is in progress.
00254  *
00255  * Example use:
00256  *  SMARTLIST_FOREACH_JOIN(routerstatus_list, routerstatus_t *, rs,
00257  *                     routerinfo_list, routerinfo_t *, ri,
00258  *                    tor_memcmp(rs->identity_digest, ri->identity_digest, 20),
00259  *                     log_info(LD_GENERAL,"No match for %s", ri->nickname)) {
00260  *    log_info(LD_GENERAL, "%s matches routerstatus %p", ri->nickname, rs);
00261  * } SMARTLIST_FOREACH_JOIN_END(rs, ri);
00262  **/
00263 /* The example above unpacks (approximately) to:
00264  *  int rs_sl_idx = 0, rs_sl_len = smartlist_len(routerstatus_list);
00265  *  int ri_sl_idx, ri_sl_len = smartlist_len(routerinfo_list);
00266  *  int rs_ri_cmp;
00267  *  routerstatus_t *rs;
00268  *  routerinfo_t *ri;
00269  *  for (; ri_sl_idx < ri_sl_len; ++ri_sl_idx) {
00270  *    ri = smartlist_get(routerinfo_list, ri_sl_idx);
00271  *    while (rs_sl_idx < rs_sl_len) {
00272  *      rs = smartlist_get(routerstatus_list, rs_sl_idx);
00273  *      rs_ri_cmp = tor_memcmp(rs->identity_digest, ri->identity_digest, 20);
00274  *      if (rs_ri_cmp > 0) {
00275  *        break;
00276  *      } else if (rs_ri_cmp == 0) {
00277  *        goto matched_ri;
00278  *      } else {
00279  *        ++rs_sl_idx;
00280  *      }
00281  *    }
00282  *    log_info(LD_GENERAL,"No match for %s", ri->nickname);
00283  *    continue;
00284  *   matched_ri: {
00285  *    log_info(LD_GENERAL,"%s matches with routerstatus %p",ri->nickname,rs);
00286  *    }
00287  *  }
00288  */
00289 #define SMARTLIST_FOREACH_JOIN(sl1, type1, var1, sl2, type2, var2,      \
00290                                 cmpexpr, unmatched_var2)                \
00291   STMT_BEGIN                                                            \
00292   int var1 ## _sl_idx = 0, var1 ## _sl_len=(sl1)->num_used;             \
00293   int var2 ## _sl_idx = 0, var2 ## _sl_len=(sl2)->num_used;             \
00294   int var1 ## _ ## var2 ## _cmp;                                        \
00295   type1 var1;                                                           \
00296   type2 var2;                                                           \
00297   for (; var2##_sl_idx < var2##_sl_len; ++var2##_sl_idx) {              \
00298     var2 = (sl2)->list[var2##_sl_idx];                                  \
00299     while (var1##_sl_idx < var1##_sl_len) {                             \
00300       var1 = (sl1)->list[var1##_sl_idx];                                \
00301       var1##_##var2##_cmp = (cmpexpr);                                  \
00302       if (var1##_##var2##_cmp > 0) {                                    \
00303         break;                                                          \
00304       } else if (var1##_##var2##_cmp == 0) {                            \
00305         goto matched_##var2;                                            \
00306       } else {                                                          \
00307         ++var1##_sl_idx;                                                \
00308       }                                                                 \
00309     }                                                                   \
00310     /* Ran out of v1, or no match for var2. */                          \
00311     unmatched_var2;                                                     \
00312     continue;                                                           \
00313     matched_##var2: ;                                                   \
00314 
00315 #define SMARTLIST_FOREACH_JOIN_END(var1, var2)  \
00316   }                                             \
00317   STMT_END
00318 
00319 #define DECLARE_MAP_FNS(maptype, keytype, prefix)                       \
00320   typedef struct maptype maptype;                                       \
00321   typedef struct prefix##entry_t *prefix##iter_t;                       \
00322   maptype* prefix##new(void);                                           \
00323   void* prefix##set(maptype *map, keytype key, void *val);              \
00324   void* prefix##get(const maptype *map, keytype key);                   \
00325   void* prefix##remove(maptype *map, keytype key);                      \
00326   void prefix##free(maptype *map, void (*free_val)(void*));             \
00327   int prefix##isempty(const maptype *map);                              \
00328   int prefix##size(const maptype *map);                                 \
00329   prefix##iter_t *prefix##iter_init(maptype *map);                      \
00330   prefix##iter_t *prefix##iter_next(maptype *map, prefix##iter_t *iter); \
00331   prefix##iter_t *prefix##iter_next_rmv(maptype *map, prefix##iter_t *iter); \
00332   void prefix##iter_get(prefix##iter_t *iter, keytype *keyp, void **valp); \
00333   int prefix##iter_done(prefix##iter_t *iter);                          \
00334   void prefix##assert_ok(const maptype *map)
00335 
00336 /* Map from const char * to void *. Implemented with a hash table. */
00337 DECLARE_MAP_FNS(strmap_t, const char *, strmap_);
00338 /* Map from const char[DIGEST_LEN] to void *. Implemented with a hash table. */
00339 DECLARE_MAP_FNS(digestmap_t, const char *, digestmap_);
00340 
00341 #undef DECLARE_MAP_FNS
00342 
00353 /* Unpacks to, approximately:
00354  * {
00355  *   digestmap_iter_t *k_iter;
00356  *   for (k_iter = digestmap_iter_init(m); !digestmap_iter_done(k_iter);
00357  *        k_iter = digestmap_iter_next(m, k_iter)) {
00358  *     const char *k;
00359  *     void *r_voidp;
00360  *     routerinfo_t *r;
00361  *     digestmap_iter_get(k_iter, &k, &r_voidp);
00362  *     r = r_voidp;
00363  *     // use k and r
00364  *   }
00365  * }
00366  */
00367 #define MAP_FOREACH(prefix, map, keytype, keyvar, valtype, valvar)      \
00368   STMT_BEGIN                                                            \
00369     prefix##iter_t *keyvar##_iter;                                      \
00370     for (keyvar##_iter = prefix##iter_init(map);                        \
00371          !prefix##iter_done(keyvar##_iter);                             \
00372          keyvar##_iter = prefix##iter_next(map, keyvar##_iter)) {       \
00373       keytype keyvar;                                                   \
00374       void *valvar##_voidp;                                             \
00375       valtype valvar;                                                   \
00376       prefix##iter_get(keyvar##_iter, &keyvar, &valvar##_voidp);        \
00377       valvar = valvar##_voidp;
00378 
00388 /* Unpacks to, approximately:
00389  * {
00390  *   digestmap_iter_t *k_iter;
00391  *   int k_del=0;
00392  *   for (k_iter = digestmap_iter_init(m); !digestmap_iter_done(k_iter);
00393  *        k_iter = k_del ? digestmap_iter_next(m, k_iter)
00394  *                       : digestmap_iter_next_rmv(m, k_iter)) {
00395  *     const char *k;
00396  *     void *r_voidp;
00397  *     routerinfo_t *r;
00398  *     k_del=0;
00399  *     digestmap_iter_get(k_iter, &k, &r_voidp);
00400  *     r = r_voidp;
00401  *     if (is_very_old(r)) {
00402  *       k_del = 1;
00403  *     }
00404  *   }
00405  * }
00406  */
00407 #define MAP_FOREACH_MODIFY(prefix, map, keytype, keyvar, valtype, valvar) \
00408   STMT_BEGIN                                                            \
00409     prefix##iter_t *keyvar##_iter;                                      \
00410     int keyvar##_del=0;                                                 \
00411     for (keyvar##_iter = prefix##iter_init(map);                        \
00412          !prefix##iter_done(keyvar##_iter);                             \
00413          keyvar##_iter = keyvar##_del ?                                 \
00414            prefix##iter_next_rmv(map, keyvar##_iter) :                  \
00415            prefix##iter_next(map, keyvar##_iter)) {                     \
00416       keytype keyvar;                                                   \
00417       void *valvar##_voidp;                                             \
00418       valtype valvar;                                                   \
00419       keyvar##_del=0;                                                   \
00420       prefix##iter_get(keyvar##_iter, &keyvar, &valvar##_voidp);        \
00421       valvar = valvar##_voidp;
00422 
00425 #define MAP_DEL_CURRENT(keyvar)                   \
00426   STMT_BEGIN                                      \
00427     keyvar##_del = 1;                             \
00428   STMT_END
00429 
00431 #define MAP_FOREACH_END } STMT_END ;
00432 
00439 #define DIGESTMAP_FOREACH(map, keyvar, valtype, valvar)                 \
00440   MAP_FOREACH(digestmap_, map, const char *, keyvar, valtype, valvar)
00441 
00450 #define DIGESTMAP_FOREACH_MODIFY(map, keyvar, valtype, valvar)          \
00451   MAP_FOREACH_MODIFY(digestmap_, map, const char *, keyvar, valtype, valvar)
00452 
00453 #define DIGESTMAP_FOREACH_END MAP_FOREACH_END
00454 
00455 #define STRMAP_FOREACH(map, keyvar, valtype, valvar)                 \
00456   MAP_FOREACH(strmap_, map, const char *, keyvar, valtype, valvar)
00457 #define STRMAP_FOREACH_MODIFY(map, keyvar, valtype, valvar)          \
00458   MAP_FOREACH_MODIFY(strmap_, map, const char *, keyvar, valtype, valvar)
00459 #define STRMAP_FOREACH_END MAP_FOREACH_END
00460 
00461 void* strmap_set_lc(strmap_t *map, const char *key, void *val);
00462 void* strmap_get_lc(const strmap_t *map, const char *key);
00463 void* strmap_remove_lc(strmap_t *map, const char *key);
00464 
00465 #define DECLARE_TYPED_DIGESTMAP_FNS(prefix, maptype, valtype)           \
00466   typedef struct maptype maptype;                                       \
00467   typedef struct prefix##iter_t prefix##iter_t;                         \
00468   static INLINE maptype* prefix##new(void)                              \
00469   {                                                                     \
00470     return (maptype*)digestmap_new();                                   \
00471   }                                                                     \
00472   static INLINE digestmap_t* prefix##to_digestmap(maptype *map)         \
00473   {                                                                     \
00474     return (digestmap_t*)map;                                           \
00475   }                                                                     \
00476   static INLINE valtype* prefix##get(maptype *map, const char *key)     \
00477   {                                                                     \
00478     return (valtype*)digestmap_get((digestmap_t*)map, key);             \
00479   }                                                                     \
00480   static INLINE valtype* prefix##set(maptype *map, const char *key,     \
00481                                      valtype *val)                      \
00482   {                                                                     \
00483     return (valtype*)digestmap_set((digestmap_t*)map, key, val);        \
00484   }                                                                     \
00485   static INLINE valtype* prefix##remove(maptype *map, const char *key)  \
00486   {                                                                     \
00487     return (valtype*)digestmap_remove((digestmap_t*)map, key);          \
00488   }                                                                     \
00489   static INLINE void prefix##free(maptype *map, void (*free_val)(void*)) \
00490   {                                                                     \
00491     digestmap_free((digestmap_t*)map, free_val);                        \
00492   }                                                                     \
00493   static INLINE int prefix##isempty(maptype *map)                       \
00494   {                                                                     \
00495     return digestmap_isempty((digestmap_t*)map);                        \
00496   }                                                                     \
00497   static INLINE int prefix##size(maptype *map)                          \
00498   {                                                                     \
00499     return digestmap_size((digestmap_t*)map);                           \
00500   }                                                                     \
00501   static INLINE prefix##iter_t *prefix##iter_init(maptype *map)         \
00502   {                                                                     \
00503     return (prefix##iter_t*) digestmap_iter_init((digestmap_t*)map);    \
00504   }                                                                     \
00505   static INLINE prefix##iter_t *prefix##iter_next(maptype *map,         \
00506                                                   prefix##iter_t *iter) \
00507   {                                                                     \
00508     return (prefix##iter_t*) digestmap_iter_next(                       \
00509                        (digestmap_t*)map, (digestmap_iter_t*)iter);     \
00510   }                                                                     \
00511   static INLINE prefix##iter_t *prefix##iter_next_rmv(maptype *map,     \
00512                                                   prefix##iter_t *iter) \
00513   {                                                                     \
00514     return (prefix##iter_t*) digestmap_iter_next_rmv(                   \
00515                        (digestmap_t*)map, (digestmap_iter_t*)iter);     \
00516   }                                                                     \
00517   static INLINE void prefix##iter_get(prefix##iter_t *iter,             \
00518                                       const char **keyp,                \
00519                                       valtype **valp)                   \
00520   {                                                                     \
00521     void *v;                                                            \
00522     digestmap_iter_get((digestmap_iter_t*) iter, keyp, &v);             \
00523     *valp = v;                                                          \
00524   }                                                                     \
00525   static INLINE int prefix##iter_done(prefix##iter_t *iter)             \
00526   {                                                                     \
00527     return digestmap_iter_done((digestmap_iter_t*)iter);                \
00528   }
00529 
00530 #if SIZEOF_INT == 4
00531 #define BITARRAY_SHIFT 5
00532 #elif SIZEOF_INT == 8
00533 #define BITARRAY_SHIFT 6
00534 #else
00535 #error "int is neither 4 nor 8 bytes. I can't deal with that."
00536 #endif
00537 #define BITARRAY_MASK ((1u<<BITARRAY_SHIFT)-1)
00538 
00540 typedef unsigned int bitarray_t;
00542 static INLINE bitarray_t *
00543 bitarray_init_zero(unsigned int n_bits)
00544 {
00545   /* round up to the next int. */
00546   size_t sz = (n_bits+BITARRAY_MASK) >> BITARRAY_SHIFT;
00547   return tor_malloc_zero(sz*sizeof(unsigned int));
00548 }
00552 static INLINE bitarray_t *
00553 bitarray_expand(bitarray_t *ba,
00554                 unsigned int n_bits_old, unsigned int n_bits_new)
00555 {
00556   size_t sz_old = (n_bits_old+BITARRAY_MASK) >> BITARRAY_SHIFT;
00557   size_t sz_new = (n_bits_new+BITARRAY_MASK) >> BITARRAY_SHIFT;
00558   char *ptr;
00559   if (sz_new <= sz_old)
00560     return ba;
00561   ptr = tor_realloc(ba, sz_new*sizeof(unsigned int));
00562   /* This memset does nothing to the older excess bytes.  But they were
00563    * already set to 0 by bitarry_init_zero. */
00564   memset(ptr+sz_old*sizeof(unsigned int), 0,
00565          (sz_new-sz_old)*sizeof(unsigned int));
00566   return (bitarray_t*) ptr;
00567 }
00569 static INLINE void
00570 bitarray_free(bitarray_t *ba)
00571 {
00572   tor_free(ba);
00573 }
00575 static INLINE void
00576 bitarray_set(bitarray_t *b, int bit)
00577 {
00578   b[bit >> BITARRAY_SHIFT] |= (1u << (bit & BITARRAY_MASK));
00579 }
00581 static INLINE void
00582 bitarray_clear(bitarray_t *b, int bit)
00583 {
00584   b[bit >> BITARRAY_SHIFT] &= ~ (1u << (bit & BITARRAY_MASK));
00585 }
00588 static INLINE unsigned int
00589 bitarray_is_set(bitarray_t *b, int bit)
00590 {
00591   return b[bit >> BITARRAY_SHIFT] & (1u << (bit & BITARRAY_MASK));
00592 }
00593 
00595 typedef struct {
00596   int mask; 
00598   bitarray_t *ba; 
00599 } digestset_t;
00600 
00601 #define BIT(n) ((n) & set->mask)
00602 
00603 static INLINE void
00604 digestset_add(digestset_t *set, const char *digest)
00605 {
00606   const uint32_t *p = (const uint32_t *)digest;
00607   const uint32_t d1 = p[0] + (p[1]>>16);
00608   const uint32_t d2 = p[1] + (p[2]>>16);
00609   const uint32_t d3 = p[2] + (p[3]>>16);
00610   const uint32_t d4 = p[3] + (p[0]>>16);
00611   bitarray_set(set->ba, BIT(d1));
00612   bitarray_set(set->ba, BIT(d2));
00613   bitarray_set(set->ba, BIT(d3));
00614   bitarray_set(set->ba, BIT(d4));
00615 }
00616 
00619 static INLINE int
00620 digestset_isin(const digestset_t *set, const char *digest)
00621 {
00622   const uint32_t *p = (const uint32_t *)digest;
00623   const uint32_t d1 = p[0] + (p[1]>>16);
00624   const uint32_t d2 = p[1] + (p[2]>>16);
00625   const uint32_t d3 = p[2] + (p[3]>>16);
00626   const uint32_t d4 = p[3] + (p[0]>>16);
00627   return bitarray_is_set(set->ba, BIT(d1)) &&
00628          bitarray_is_set(set->ba, BIT(d2)) &&
00629          bitarray_is_set(set->ba, BIT(d3)) &&
00630          bitarray_is_set(set->ba, BIT(d4));
00631 }
00632 #undef BIT
00633 
00634 digestset_t *digestset_new(int max_elements);
00635 void digestset_free(digestset_t* set);
00636 
00637 /* These functions, given an <b>array</b> of <b>n_elements</b>, return the
00638  * <b>nth</b> lowest element. <b>nth</b>=0 gives the lowest element;
00639  * <b>n_elements</b>-1 gives the highest; and (<b>n_elements</b>-1) / 2 gives
00640  * the median.  As a side effect, the elements of <b>array</b> are sorted. */
00641 int find_nth_int(int *array, int n_elements, int nth);
00642 time_t find_nth_time(time_t *array, int n_elements, int nth);
00643 double find_nth_double(double *array, int n_elements, int nth);
00644 int32_t find_nth_int32(int32_t *array, int n_elements, int nth);
00645 uint32_t find_nth_uint32(uint32_t *array, int n_elements, int nth);
00646 long find_nth_long(long *array, int n_elements, int nth);
00647 static INLINE int
00648 median_int(int *array, int n_elements)
00649 {
00650   return find_nth_int(array, n_elements, (n_elements-1)/2);
00651 }
00652 static INLINE time_t
00653 median_time(time_t *array, int n_elements)
00654 {
00655   return find_nth_time(array, n_elements, (n_elements-1)/2);
00656 }
00657 static INLINE double
00658 median_double(double *array, int n_elements)
00659 {
00660   return find_nth_double(array, n_elements, (n_elements-1)/2);
00661 }
00662 static INLINE uint32_t
00663 median_uint32(uint32_t *array, int n_elements)
00664 {
00665   return find_nth_uint32(array, n_elements, (n_elements-1)/2);
00666 }
00667 static INLINE int32_t
00668 median_int32(int32_t *array, int n_elements)
00669 {
00670   return find_nth_int32(array, n_elements, (n_elements-1)/2);
00671 }
00672 static INLINE long
00673 median_long(long *array, int n_elements)
00674 {
00675   return find_nth_long(array, n_elements, (n_elements-1)/2);
00676 }
00677 
00678 #endif
00679