Stxxl
1.4.0
|
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