Stxxl  1.3.2
losertree.h
1 /***************************************************************************
2  * include/stxxl/bits/algo/losertree.h
3  *
4  * Part of the STXXL. See http://stxxl.sourceforge.net
5  *
6  * Copyright (C) 1999 Peter Sanders <[email protected]>
7  * Copyright (C) 2002 Roman Dementiev <[email protected]>
8  * Copyright (C) 2009 Andreas Beckmann <[email protected]>
9  *
10  * Distributed under the Boost Software License, Version 1.0.
11  * (See accompanying file LICENSE_1_0.txt or copy at
12  * http://www.boost.org/LICENSE_1_0.txt)
13  **************************************************************************/
14 
15 #ifndef STXXL_LOSERTREE_HEADER
16 #define STXXL_LOSERTREE_HEADER
17 
18 #include <algorithm>
19 #include <stxxl/bits/noncopyable.h>
20 #include <stxxl/bits/common/utils.h>
21 #include <stxxl/bits/verbose.h>
22 
23 
24 __STXXL_BEGIN_NAMESPACE
25 
26 template <typename run_cursor_type,
27  typename run_cursor_cmp_type>
28 class loser_tree : private noncopyable
29 {
30  int logK;
31  int_type k;
32  int_type * entry;
33  run_cursor_type * current;
34  run_cursor_cmp_type cmp;
35 
36  int_type init_winner(int_type root)
37  {
38  if (root >= k)
39  {
40  return root - k;
41  }
42  else
43  {
44  int_type left = init_winner(2 * root);
45  int_type right = init_winner(2 * root + 1);
46  if (cmp(current[left], current[right]))
47  {
48  entry[root] = right;
49  return left;
50  }
51  else
52  {
53  entry[root] = left;
54  return right;
55  }
56  }
57  }
58 
59 public:
60  typedef typename run_cursor_type::prefetcher_type prefetcher_type;
61  typedef typename run_cursor_type::value_type value_type;
62 
63  loser_tree(
64  prefetcher_type * p,
65  int_type nruns,
66  run_cursor_cmp_type c) : cmp(c)
67  {
68  int_type i;
69  logK = log2_ceil(nruns);
70  int_type kReg = k = (1 << logK);
71 
72  STXXL_VERBOSE2("loser_tree: logK=" << logK << " nruns=" << nruns << " K=" << kReg);
73 
74 #ifdef STXXL_SORT_SINGLE_PREFETCHER
75  current = new run_cursor_type[kReg];
76  run_cursor_type::set_prefetcher(p);
77 #else
78  current = new run_cursor_type[kReg];
79  for (i = 0; i < kReg; ++i)
80  current[i].prefetcher() = p;
81 #endif
82  entry = new int_type[(kReg << 1)];
83  // init cursors
84  for (i = 0; i < nruns; ++i)
85  {
86  current[i].buffer = p->pull_block();
87  //current[i].pos = 0; // done in constructor
88  entry[kReg + i] = i;
89  }
90 
91  for (i = nruns; i < kReg; ++i)
92  {
93  current[i].make_inf();
94  entry[kReg + i] = i;
95  }
96 
97  entry[0] = init_winner(1);
98  }
99  ~loser_tree()
100  {
101  delete[] current;
102  delete[] entry;
103  }
104 
105  void swap(loser_tree & obj)
106  {
107  std::swap(logK, obj.logK);
108  std::swap(k, obj.k);
109  std::swap(entry, obj.entry);
110  std::swap(current, obj.current);
111  std::swap(cmp, obj.cmp);
112  }
113 
114 private:
115  template <unsigned LogK>
116  void multi_merge_unrolled(value_type * out_first, value_type * out_last)
117  {
118  run_cursor_type * currentE, * winnerE;
119  int_type * regEntry = entry;
120  int_type winnerIndex = regEntry[0];
121 
122  while (LIKELY(out_first != out_last))
123  {
124  winnerE = current + winnerIndex;
125  *(out_first) = winnerE->current();
126  ++out_first;
127 
128  ++(*winnerE);
129 
130 
131 #define TreeStep(L) \
132  if (LogK >= L) \
133  { \
134  currentE = current + \
135  regEntry[(winnerIndex + (1 << LogK)) >> (((int(LogK - L) + 1) >= 0) ? ((LogK - L) + 1) : 0)]; \
136  if (cmp(*currentE, *winnerE)) \
137  { \
138  std::swap(regEntry[(winnerIndex + (1 << LogK)) \
139  >> (((int(LogK - L) + 1) >= 0) ? ((LogK - L) + 1) : 0)], winnerIndex); \
140  winnerE = currentE; \
141  } \
142  }
143 
144  TreeStep(10);
145  TreeStep(9);
146  TreeStep(8);
147  TreeStep(7);
148  TreeStep(6);
149  TreeStep(5);
150  TreeStep(4);
151  TreeStep(3);
152  TreeStep(2);
153  TreeStep(1);
154 
155 #undef TreeStep
156  }
157 
158  regEntry[0] = winnerIndex;
159  }
160 
161  void multi_merge_unrolled_0(value_type * out_first, value_type * out_last)
162  {
163  while (LIKELY(out_first != out_last))
164  {
165  *out_first = current->current();
166  ++out_first;
167  ++(*current);
168  }
169  }
170 
171  void multi_merge_k(value_type * out_first, value_type * out_last)
172  {
173  run_cursor_type * currentE, * winnerE;
174  int_type kReg = k;
175  int_type winnerIndex = entry[0];
176 
177  while (LIKELY(out_first != out_last))
178  {
179  winnerE = current + winnerIndex;
180  *(out_first) = winnerE->current();
181  ++out_first;
182 
183  ++(*winnerE);
184 
185  for (int_type i = (winnerIndex + kReg) >> 1; i > 0; i >>= 1)
186  {
187  currentE = current + entry[i];
188 
189  if (cmp(*currentE, *winnerE))
190  {
191  std::swap(entry[i], winnerIndex);
192  winnerE = currentE;
193  }
194  }
195  }
196 
197  entry[0] = winnerIndex;
198  }
199 
200 public:
201  void multi_merge(value_type * out_first, value_type * out_last)
202  {
203  switch (logK)
204  {
205  case 0:
206  multi_merge_unrolled_0(out_first, out_last);
207  break;
208  case 1:
209  multi_merge_unrolled<1>(out_first, out_last);
210  break;
211  case 2:
212  multi_merge_unrolled<2>(out_first, out_last);
213  break;
214  case 3:
215  multi_merge_unrolled<3>(out_first, out_last);
216  break;
217  case 4:
218  multi_merge_unrolled<4>(out_first, out_last);
219  break;
220  case 5:
221  multi_merge_unrolled<5>(out_first, out_last);
222  break;
223  case 6:
224  multi_merge_unrolled<6>(out_first, out_last);
225  break;
226  case 7:
227  multi_merge_unrolled<7>(out_first, out_last);
228  break;
229  case 8:
230  multi_merge_unrolled<8>(out_first, out_last);
231  break;
232  case 9:
233  multi_merge_unrolled<9>(out_first, out_last);
234  break;
235  case 10:
236  multi_merge_unrolled<10>(out_first, out_last);
237  break;
238  default:
239  multi_merge_k(out_first, out_last);
240  break;
241  }
242  }
243 };
244 
245 __STXXL_END_NAMESPACE
246 
247 namespace std
248 {
249  template <typename run_cursor_type,
250  typename run_cursor_cmp_type>
251  void swap(stxxl::loser_tree<run_cursor_type, run_cursor_cmp_type> & a,
252  stxxl::loser_tree<run_cursor_type, run_cursor_cmp_type> & b)
253  {
254  a.swap(b);
255  }
256 }
257 
258 #endif // !STXXL_LOSERTREE_HEADER
259 // vim: et:ts=4:sw=4