00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
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
00084 for (i = 0; i < nruns; ++i)
00085 {
00086 current[i].buffer = p->pull_block();
00087
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