STXXL  1.4-dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
pq_int_merger.h
Go to the documentation of this file.
1 /***************************************************************************
2  * include/stxxl/bits/containers/pq_int_merger.h
3  *
4  * Part of the STXXL. See http://stxxl.sourceforge.net
5  *
6  * Copyright (C) 1999 Peter Sanders <[email protected]>
7  * Copyright (C) 2003, 2004, 2007 Roman Dementiev <[email protected]>
8  * Copyright (C) 2007-2009 Johannes Singler <[email protected]>
9  * Copyright (C) 2007, 2008 Andreas Beckmann <[email protected]>
10  *
11  * Distributed under the Boost Software License, Version 1.0.
12  * (See accompanying file LICENSE_1_0.txt or copy at
13  * http://www.boost.org/LICENSE_1_0.txt)
14  **************************************************************************/
15 
16 #ifndef STXXL_CONTAINERS_PQ_INT_MERGER_HEADER
17 #define STXXL_CONTAINERS_PQ_INT_MERGER_HEADER
18 
20 
22 
23 //! \addtogroup stlcontinternals
24 //!
25 //! \{
26 
27 /*! \internal
28  */
29 namespace priority_queue_local {
30 
31 template <class ValueType, class CompareType, unsigned MaxArity>
32 class int_merger : private noncopyable
33 {
34 public:
35  //! type of values in merger
36  typedef ValueType value_type;
37  //! comparator object type
38  typedef CompareType compare_type;
39 
40  enum { max_arity = MaxArity };
41 
42  //! our type
44 
45 #if STXXL_PARALLEL && STXXL_PARALLEL_PQ_MULTIWAY_MERGE_INTERNAL
46  //! type of embedded adapter to parallel multiway_merge
47  typedef parallel_merger_adapter<self_type, CompareType, MaxArity> tree_type;
48 #else
49  //! type of embedded loser tree
51 #endif
52 
53  //! type of sequences in which the values are stored: memory arrays
55 
56  //! size type of total number of item in merger
58 
59 protected:
60  //! loser tree instance
62 
63  //! target of free segment pointers
65 
66  // leaf information. note that Knuth uses indices k..k-1, while we use
67  // 0..k-1
68 
69  //! pointer to current element
70  value_type* current[MaxArity];
71  //! pointer to end of block for current element
72  value_type* current_end[MaxArity];
73  //! start of Segments
74  value_type* segment[MaxArity];
75  //! just to count the internal memory consumption, in bytes
76  unsigned_type segment_size[MaxArity];
77 
79 
80  //! total number of elements stored
82 
83 public:
84  //! \name Interface for loser_tree
85  //! \{
86 
87  //! is this array invalid? here: empty and prefixed with sentinel?
88  bool is_array_empty(unsigned_type slot) const
89  {
90  return tree.is_sentinel(*(current[slot]));
91  }
92 
93  //! is this array's backing memory still allocated or does the current
94  //! point to sentinel?
96  {
97  return current[slot] != &sentinel;
98  }
99 
100  //! Return the item sequence of the given slot
102  {
103  return current[slot];
104  }
105 
106  //! Swap contents of arrays a and b
108  {
109  std::swap(current[a], current[b]);
110  std::swap(current_end[a], current_end[b]);
111  std::swap(segment[a], segment[b]);
112  std::swap(segment_size[a], segment_size[b]);
113  }
114 
115  //! Set a usually empty array to the sentinel
117  {
118  current[slot] = &sentinel;
119  current_end[slot] = &sentinel;
120  segment[slot] = NULL;
121  }
122 
123  //! free an empty segment .
125  {
126  // reroute current pointer to some empty sentinel segment
127  // with a sentinel key
128  STXXL_VERBOSE2("int_merger::free_array() deleting array " <<
129  slot << " address: " << segment[slot] << " size: " << (segment_size[slot] / sizeof(value_type)) - 1);
130  current[slot] = &sentinel;
131  current_end[slot] = &sentinel;
132 
133  // free memory
134  delete[] segment[slot];
135  segment[slot] = NULL;
136  mem_cons_ -= segment_size[slot];
137 
138  // free player in loser tree
139  tree.free_player(slot);
140  }
141 
142  //! Hint (prefetch) first non-internal (actually second) block of each
143  //! sequence. No-operation for internal arrays.
145  { }
146 
147  //! \}
148 
149 public:
150  int_merger(const compare_type& c = compare_type())
151  : tree(c, *this),
152  sentinel(c.min_value()),
153  mem_cons_(0),
154  m_size(0)
155  {
156  segment[0] = NULL;
157  current[0] = &sentinel;
158  current_end[0] = &sentinel;
159 
160  // entry and sentinel are initialized by init since they need the value
161  // of supremum
162  tree.initialize();
163  }
164 
166  {
167  STXXL_VERBOSE1("int_merger::~int_merger()");
168  for (unsigned_type i = 0; i < tree.k; ++i)
169  {
170  if (segment[i])
171  {
172  STXXL_VERBOSE2("int_merger::~int_merger() deleting segment " << i);
173  delete[] segment[i];
174  mem_cons_ -= segment_size[i];
175  }
176  }
177  // check whether we have not lost any memory
178  assert(mem_cons_ == 0);
179  }
180 
181  void swap(int_merger& obj)
182  {
183  std::swap(sentinel, obj.sentinel);
184  swap_1D_arrays(current, obj.current, MaxArity);
185  swap_1D_arrays(current_end, obj.current_end, MaxArity);
186  swap_1D_arrays(segment, obj.segment, MaxArity);
187  swap_1D_arrays(segment_size, obj.segment_size, MaxArity);
188  std::swap(mem_cons_, obj.mem_cons_);
189  }
190 
191  unsigned_type mem_cons() const { return mem_cons_; }
192 
193  //! Whether there is still space for new array
194  bool is_space_available() const
195  {
196  return tree.is_space_available();
197  }
198 
199  //! True if a is the sentinel value
200  bool is_sentinel(const value_type& a) const
201  {
202  return tree.is_sentinel(a);
203  }
204 
205  //! append array to merger, takes ownership of the array.
206  //! requires: is_space_available() == 1
207  void append_array(value_type* target, unsigned_type length)
208  {
209  STXXL_VERBOSE2("int_merger::insert_segment(" << target << "," << length << ")");
210  //std::copy(target,target + length,std::ostream_iterator<ValueType>(std::cout, "\n"));
211 
212  if (length == 0)
213  {
214  // immediately deallocate this is not only an optimization but also
215  // needed to keep free segments from clogging up the tree
216  delete[] target;
217  return;
218  }
219 
220  assert(!tree.is_sentinel(target[0]));
221  assert(!tree.is_sentinel(target[length - 1]));
222  assert(tree.is_sentinel(target[length]));
223 
224  // allocate a new player slot
225  unsigned_type index = tree.new_player();
226 
227  assert(current[index] == &sentinel);
228 
229  // link new segment
230  current[index] = segment[index] = target;
231  current_end[index] = target + length;
232  segment_size[index] = (length + 1) * sizeof(value_type);
233  mem_cons_ += (length + 1) * sizeof(value_type);
234  m_size += length;
235 
236  // propagate new information up the tree
237  tree.update_on_insert((index + tree.k) >> 1, *target, index);
238  }
239 
240  //! Return the number of items in the arrays
241  size_type size() const
242  {
243  return m_size;
244  }
245 
246  //! extract the (length = end - begin) smallest elements and write them to
247  //! [begin..end) empty segments are deallocated. Requires: there are at
248  //! least length elements and segments are ended by sentinels.
249  void multi_merge(value_type* begin, value_type* end)
250  {
251  assert(begin + m_size >= end);
252 
253 #if STXXL_PARALLEL && STXXL_PARALLEL_PQ_MULTIWAY_MERGE_INTERNAL
254  multi_merge_parallel(begin, end - begin);
255 #else
256  tree.multi_merge(begin, end);
257 #endif
258 
259  m_size -= end - begin;
260  }
261 
262 #if STXXL_PARALLEL && STXXL_PARALLEL_PQ_MULTIWAY_MERGE_INTERNAL
263 
264 protected:
265  //! extract the (length = end - begin) smallest elements using parallel
266  //! multiway_merge.
267  void multi_merge_parallel(value_type* target, unsigned_type length)
268  {
269  const unsigned_type& k = tree.k;
270  const unsigned_type& logK = tree.logK;
271  compare_type& cmp = tree.cmp;
272 
273  STXXL_VERBOSE3("int_merger::multi_merge_parallel(target=" << target << ", len=" << length << ") k=" << k);
274 
275  if (length == 0)
276  return;
277 
278  assert(k > 0);
279 
280  //This is the place to make statistics about internal multi_merge calls.
281 
283  switch (logK) {
284  case 0: {
285  assert(k == 1);
286 
287  memcpy(target, current[0], length * sizeof(value_type));
288  current[0] += length;
289 
290  if (is_array_empty(0) && is_array_allocated(0))
291  free_array(0);
292 
293  break;
294  }
295  case 1: {
296  assert(k == 2);
297 
298  std::pair<value_type*, value_type*> seqs[2] =
299  {
300  std::make_pair(current[0], current_end[0]),
301  std::make_pair(current[1], current_end[1])
302  };
303 
305  seqs, seqs + 2, target, length, inv_cmp);
306 
307  current[0] = seqs[0].first;
308  current[1] = seqs[1].first;
309 
310  if (is_array_empty(0) && is_array_allocated(0))
311  free_array(0);
312 
313  if (is_array_empty(1) && is_array_allocated(1))
314  free_array(1);
315 
316  break;
317  }
318  case 2: {
319  assert(k == 4);
320 
321  std::pair<value_type*, value_type*> seqs[4] =
322  {
323  std::make_pair(current[0], current_end[0]),
324  std::make_pair(current[1], current_end[1]),
325  std::make_pair(current[2], current_end[2]),
326  std::make_pair(current[3], current_end[3])
327  };
328 
330  seqs, seqs + 4, target, length, inv_cmp);
331 
332  current[0] = seqs[0].first;
333  current[1] = seqs[1].first;
334  current[2] = seqs[2].first;
335  current[3] = seqs[3].first;
336 
337  if (is_array_empty(0) && is_array_allocated(0))
338  free_array(0);
339 
340  if (is_array_empty(1) && is_array_allocated(1))
341  free_array(1);
342 
343  if (is_array_empty(2) && is_array_allocated(2))
344  free_array(2);
345 
346  if (is_array_empty(3) && is_array_allocated(3))
347  free_array(3);
348 
349  break;
350  }
351  default: {
352  std::vector<std::pair<value_type*, value_type*> > seqs;
353  std::vector<int_type> orig_seq_index;
354  for (unsigned int i = 0; i < k; ++i)
355  {
356  if (current[i] != current_end[i] && !is_sentinel(*current[i]))
357  {
358  seqs.push_back(std::make_pair(current[i], current_end[i]));
359  orig_seq_index.push_back(i);
360  }
361  }
362 
364  seqs.begin(), seqs.end(), target, length, inv_cmp);
365 
366  for (unsigned int i = 0; i < seqs.size(); ++i)
367  {
368  int_type seg = orig_seq_index[i];
369  current[seg] = seqs[i].first;
370  }
371 
372  for (unsigned int i = 0; i < k; ++i)
373  {
374  if (is_array_empty(i) && is_array_allocated(i))
375  {
376  STXXL_VERBOSE3("deallocated " << i);
377  free_array(i);
378  }
379  }
380  break;
381  }
382  }
383 
384  tree.maybe_compact();
385  }
386 #endif // STXXL_PARALLEL && STXXL_PARALLEL_PQ_MULTIWAY_MERGE_INTERNAL
387 };
388 
389 } // namespace priority_queue_local
390 
391 //! \}
392 
394 
395 #endif // !STXXL_CONTAINERS_PQ_INT_MERGER_HEADER
396 // vim: et:ts=4:sw=4
bool is_array_allocated(unsigned_type slot) const
is this array&#39;s backing memory still allocated or does the current point to sentinel?
Definition: pq_int_merger.h:95
size_type m_size
total number of elements stored
Definition: pq_int_merger.h:81
void prefetch_arrays()
Hint (prefetch) first non-internal (actually second) block of each sequence. No-operation for interna...
void append_array(value_type *target, unsigned_type length)
append array to merger, takes ownership of the array. requires: is_space_available() == 1 ...
Inverts the order of a comparison functor by swapping its arguments.
Definition: pq_helpers.h:187
loser_tree< self_type, CompareType, MaxArity > tree_type
type of embedded loser tree
Definition: pq_int_merger.h:50
bool is_sentinel(const value_type &a) const
True if a is the sentinel value.
bool is_array_empty(unsigned_type slot) const
is this array invalid? here: empty and prefixed with sentinel?
Definition: pq_int_merger.h:88
void swap_1D_arrays(Type *a, Type *b, unsigned_type size)
Definition: utils.h:246
tree_type tree
loser tree instance
Definition: pq_int_merger.h:61
#define STXXL_VERBOSE2(x)
Definition: verbose.h:121
void multi_merge(value_type *begin, value_type *end)
extract the (length = end - begin) smallest elements and write them to [begin..end) empty segments ar...
void swap_arrays(unsigned_type a, unsigned_type b)
Swap contents of arrays a and b.
size_type size() const
Return the number of items in the arrays.
value_type * segment[MaxArity]
start of Segments
Definition: pq_int_merger.h:74
unsigned_type segment_size[MaxArity]
just to count the internal memory consumption, in bytes
Definition: pq_int_merger.h:76
value_type * sequence_type
type of sequences in which the values are stored: memory arrays
Definition: pq_int_merger.h:54
void make_array_sentinel(unsigned_type slot)
Set a usually empty array to the sentinel.
value_type * current_end[MaxArity]
pointer to end of block for current element
Definition: pq_int_merger.h:72
RandomAccessIterator3 multiway_merge_sentinels(RandomAccessIteratorPairIterator seqs_begin, RandomAccessIteratorPairIterator seqs_end, RandomAccessIterator3 target, DiffType length, Comparator comp)
Multi-way merging front-end.
Definition: parallel.h:195
#define STXXL_VERBOSE3(x)
Definition: verbose.h:127
choose_int_types< my_pointer_size >::int_type int_type
Definition: types.h:63
unsigned_type internal_size_type
Definition: types.h:66
#define STXXL_BEGIN_NAMESPACE
Definition: namespace.h:16
#define STXXL_VERBOSE1(x)
Definition: verbose.h:113
value_type * current[MaxArity]
pointer to current element
Definition: pq_int_merger.h:70
bool is_space_available() const
Whether there is still space for new array.
void free_array(unsigned_type slot)
free an empty segment .
choose_int_types< my_pointer_size >::unsigned_type unsigned_type
Definition: types.h:64
CompareType compare_type
comparator object type
Definition: pq_int_merger.h:38
static const size_t sentinel
value_type sentinel
target of free segment pointers
Definition: pq_int_merger.h:64
ValueType value_type
type of values in merger
Definition: pq_int_merger.h:36
int_merger< ValueType, CompareType, MaxArity > self_type
our type
Definition: pq_int_merger.h:43
sequence_type & get_array(unsigned_type slot)
Return the item sequence of the given slot.
#define STXXL_END_NAMESPACE
Definition: namespace.h:17
internal_size_type size_type
size type of total number of item in merger
Definition: pq_int_merger.h:57