Stxxl  1.4.0
include/stxxl/bits/algo/losertree.h
Go to the documentation of this file.
00001 /***************************************************************************
00002  *  include/stxxl/bits/algo/losertree.h
00003  *
00004  *  Part of the STXXL. See http://stxxl.sourceforge.net
00005  *
00006  *  Copyright (C) 1999 Peter Sanders <sanders@mpi-sb.mpg.de>
00007  *  Copyright (C) 2002 Roman Dementiev <dementiev@mpi-sb.mpg.de>
00008  *  Copyright (C) 2009 Andreas Beckmann <beckmann@cs.uni-frankfurt.de>
00009  *
00010  *  Distributed under the Boost Software License, Version 1.0.
00011  *  (See accompanying file LICENSE_1_0.txt or copy at
00012  *  http://www.boost.org/LICENSE_1_0.txt)
00013  **************************************************************************/
00014 
00015 #ifndef STXXL_LOSERTREE_HEADER
00016 #define STXXL_LOSERTREE_HEADER
00017 
00018 #include <algorithm>
00019 #include <stxxl/bits/noncopyable.h>
00020 #include <stxxl/bits/common/utils.h>
00021 #include <stxxl/bits/verbose.h>
00022 
00023 
00024 __STXXL_BEGIN_NAMESPACE
00025 
00026 template <typename run_cursor_type,
00027           typename run_cursor_cmp_type>
00028 class loser_tree : private noncopyable
00029 {
00030     int logK;
00031     int_type k;
00032     int_type * entry;
00033     run_cursor_type * current;
00034     run_cursor_cmp_type cmp;
00035 
00036     int_type init_winner(int_type root)
00037     {
00038         if (root >= k)
00039         {
00040             return root - k;
00041         }
00042         else
00043         {
00044             int_type left = init_winner(2 * root);
00045             int_type right = init_winner(2 * root + 1);
00046             if (cmp(current[left], current[right]))
00047             {
00048                 entry[root] = right;
00049                 return left;
00050             }
00051             else
00052             {
00053                 entry[root] = left;
00054                 return right;
00055             }
00056         }
00057     }
00058 
00059 public:
00060     typedef typename run_cursor_type::prefetcher_type prefetcher_type;
00061     typedef typename run_cursor_type::value_type value_type;
00062 
00063     loser_tree(
00064         prefetcher_type * p,
00065         int_type nruns,
00066         run_cursor_cmp_type c) : cmp(c)
00067     {
00068         int_type i;
00069         logK = log2_ceil(nruns);
00070         int_type kReg = k = (1 << logK);
00071 
00072         STXXL_VERBOSE2("loser_tree: logK=" << logK << " nruns=" << nruns << " K=" << kReg);
00073 
00074 #ifdef STXXL_SORT_SINGLE_PREFETCHER
00075         current = new run_cursor_type[kReg];
00076         run_cursor_type::set_prefetcher(p);
00077 #else
00078         current = new run_cursor_type[kReg];
00079         for (i = 0; i < kReg; ++i)
00080             current[i].prefetcher() = p;
00081 #endif
00082         entry = new int_type[(kReg << 1)];
00083         // init cursors
00084         for (i = 0; i < nruns; ++i)
00085         {
00086             current[i].buffer = p->pull_block();
00087             //current[i].pos = 0; // done in constructor
00088             entry[kReg + i] = i;
00089         }
00090 
00091         for (i = nruns; i < kReg; ++i)
00092         {
00093             current[i].make_inf();
00094             entry[kReg + i] = i;
00095         }
00096 
00097         entry[0] = init_winner(1);
00098     }
00099     ~loser_tree()
00100     {
00101         delete[] current;
00102         delete[] entry;
00103     }
00104 
00105     void swap(loser_tree & obj)
00106     {
00107         std::swap(logK, obj.logK);
00108         std::swap(k, obj.k);
00109         std::swap(entry, obj.entry);
00110         std::swap(current, obj.current);
00111         std::swap(cmp, obj.cmp);
00112     }
00113 
00114 private:
00115     template <unsigned LogK>
00116     void multi_merge_unrolled(value_type * out_first, value_type * out_last)
00117     {
00118         run_cursor_type * currentE, * winnerE;
00119         int_type * regEntry = entry;
00120         int_type winnerIndex = regEntry[0];
00121 
00122         while (LIKELY(out_first != out_last))
00123         {
00124             winnerE = current + winnerIndex;
00125             *(out_first) = winnerE->current();
00126             ++out_first;
00127 
00128             ++(*winnerE);
00129 
00130 
00131 #define TreeStep(L) \
00132     if (LogK >= L) \
00133     { \
00134         currentE = current + \
00135                    regEntry[(winnerIndex + (1 << LogK)) >> (((int(LogK - L) + 1) >= 0) ? ((LogK - L) + 1) : 0)]; \
00136         if (cmp(*currentE, *winnerE)) \
00137         { \
00138             std::swap(regEntry[(winnerIndex + (1 << LogK)) \
00139                                >> (((int(LogK - L) + 1) >= 0) ? ((LogK - L) + 1) : 0)], winnerIndex); \
00140             winnerE = currentE; \
00141         } \
00142     }
00143 
00144             TreeStep(10);
00145             TreeStep(9);
00146             TreeStep(8);
00147             TreeStep(7);
00148             TreeStep(6);
00149             TreeStep(5);
00150             TreeStep(4);
00151             TreeStep(3);
00152             TreeStep(2);
00153             TreeStep(1);
00154 
00155 #undef TreeStep
00156         }
00157 
00158         regEntry[0] = winnerIndex;
00159     }
00160 
00161     void multi_merge_unrolled_0(value_type * out_first, value_type * out_last)
00162     {
00163         while (LIKELY(out_first != out_last))
00164         {
00165             *out_first = current->current();
00166             ++out_first;
00167             ++(*current);
00168         }
00169     }
00170 
00171     void multi_merge_k(value_type * out_first, value_type * out_last)
00172     {
00173         run_cursor_type * currentE, * winnerE;
00174         int_type kReg = k;
00175         int_type winnerIndex = entry[0];
00176 
00177         while (LIKELY(out_first != out_last))
00178         {
00179             winnerE = current + winnerIndex;
00180             *(out_first) = winnerE->current();
00181             ++out_first;
00182 
00183             ++(*winnerE);
00184 
00185             for (int_type i = (winnerIndex + kReg) >> 1; i > 0; i >>= 1)
00186             {
00187                 currentE = current + entry[i];
00188 
00189                 if (cmp(*currentE, *winnerE))
00190                 {
00191                     std::swap(entry[i], winnerIndex);
00192                     winnerE = currentE;
00193                 }
00194             }
00195         }
00196 
00197         entry[0] = winnerIndex;
00198     }
00199 
00200 public:
00201     void multi_merge(value_type * out_first, value_type * out_last)
00202     {
00203         switch (logK)
00204         {
00205         case 0:
00206             multi_merge_unrolled_0(out_first, out_last);
00207             break;
00208         case 1:
00209             multi_merge_unrolled<1>(out_first, out_last);
00210             break;
00211         case 2:
00212             multi_merge_unrolled<2>(out_first, out_last);
00213             break;
00214         case 3:
00215             multi_merge_unrolled<3>(out_first, out_last);
00216             break;
00217         case 4:
00218             multi_merge_unrolled<4>(out_first, out_last);
00219             break;
00220         case 5:
00221             multi_merge_unrolled<5>(out_first, out_last);
00222             break;
00223         case 6:
00224             multi_merge_unrolled<6>(out_first, out_last);
00225             break;
00226         case 7:
00227             multi_merge_unrolled<7>(out_first, out_last);
00228             break;
00229         case 8:
00230             multi_merge_unrolled<8>(out_first, out_last);
00231             break;
00232         case 9:
00233             multi_merge_unrolled<9>(out_first, out_last);
00234             break;
00235         case 10:
00236             multi_merge_unrolled<10>(out_first, out_last);
00237             break;
00238         default:
00239             multi_merge_k(out_first, out_last);
00240             break;
00241         }
00242     }
00243 };
00244 
00245 __STXXL_END_NAMESPACE
00246 
00247 namespace std
00248 {
00249     template <typename run_cursor_type,
00250               typename run_cursor_cmp_type>
00251     void swap(stxxl::loser_tree<run_cursor_type, run_cursor_cmp_type> & a,
00252               stxxl::loser_tree<run_cursor_type, run_cursor_cmp_type> & b)
00253     {
00254         a.swap(b);
00255     }
00256 }
00257 
00258 #endif // !STXXL_LOSERTREE_HEADER
00259 // vim: et:ts=4:sw=4
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines