COMBINATORIAL_BLAS 1.6
 
Loading...
Searching...
No Matches
funnel.h
Go to the documentation of this file.
1// The Funnelsort Project - Cache oblivious sorting algorithm implementation
2// Copyright (C) 2005 Kristoffer Vinther
3//
4// This program is free software; you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation; either version 2 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program; if not, write to the Free Software
16// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
17
18#ifndef FUNNEL_H_INCLUDED__
19#define FUNNEL_H_INCLUDED__
20
21#include <cassert>
22#include <memory>
23#include <utility>
24#include <iterator>
25#include <functional>
26#include <stdexcept>
27#include <cmath>
28
29namespace iosort
30{
31
32typedef unsigned short height_t;
33typedef unsigned short basic_order_t;
34typedef unsigned int order_t;
35
36template<int order>
37inline height_t logc(order_t k)
38{
39 height_t h = 0;
40 for( order_t i=k-1; i; h++, i/=order );
41 return h;
42}
43/* Computes floor(log()), not ceil(log()) :( - Also beware of little- and bigendianness(?)
44template<>
45inline height_t logf<2>(order_t k)
46{
47 float f = static_cast<float>(k);
48 return static_cast<height_t>(((*reinterpret_cast<int*>(&f)) >> 23) - 127);
49}*/
50template<int order>
52{
53 order_t k = 1;
54 for( ; h; h--, k*=order );
55 return k;
56}
57template<>
59 { return 1<<h; }
60template<>
62 { return 1<<(2*h); }
63template<>
65 { return 1<<(3*h); }
66template<>
68 { return 1<<(4*h); }
69
70template<int order>
71class bfs_index
72{
73public:
74 inline bfs_index() : i(1) { }
75 inline operator order_t() const
76 { return i; }
78 { i = rhs.i; return *this; }
79 inline bool operator==(const bfs_index<order>& rhs) const
80 { return i == rhs.i; }
81 inline bool operator!=(const bfs_index<order>& rhs) const
82 { return i != rhs.i; }
83 inline void child(basic_order_t ch)
84 { i = static_cast<order_t>(order*(i-1)+ch+2); }
85 inline void parent()
86 { /*assert( i>1 );*/ i = static_cast<order_t>((i-2)/order+1); }
88 { /*assert( i>1 );*/ return static_cast<basic_order_t>((i+order-2) % order); }
89private:
90 order_t i;
91};
92
93template<int order=2>
94class default_splitter
95{
96 static const int alpha = 16;
97public:
98 template<class diff_type>
99 static inline order_t prefered_order_output(diff_type N)
100 { return static_cast<order_t>(std::sqrt(static_cast<double>(N)/alpha)); }
101 template<class diff_type>
102 static inline order_t prefered_order_input(diff_type N)
103 { assert( false ); return static_cast<order_t>(std::sqrt(static_cast<double>(N)/alpha)); }
104 static inline size_t switch_to_cache_aware()
105 { return static_cast<size_t>(alpha*(order+1)*(order+1)); }
106 static inline height_t split(height_t h)
107 { return h/2; }
108 static inline size_t out_buffer_size(order_t k)
109 { return static_cast<size_t>(alpha*k*k); }
110};
111
112template<class FwIt> struct nop_refill { template<class Merger> inline bool operator()(const Merger*, FwIt, FwIt)
113 { return false; } };
114
115
116template<class,int,class,class,class,class>
117class special_ { };
118
119template<class RanIt, int Order=2, class Splitter = default_splitter<Order>, class Pred = std::less<typename std::iterator_traits<RanIt>::value_type>, class Refiller = nop_refill<RanIt>, class Alloc = std::allocator<typename std::iterator_traits<RanIt>::value_type> >
120class merge_tree
121{
122 friend class special_<RanIt,Order,Splitter,Pred,Refiller,Alloc>;
123public:
124 typedef unsigned int order_t;
125 enum order_tag_ { order = Order };
127 typedef Splitter splitter;
128 typedef typename std::iterator_traits<RanIt>::value_type value_type;
129 typedef Alloc allocator;
130 typedef RanIt iterator;
131 typedef Pred predicate;
132 template<class NewRefiller>
134private:
135 struct Node;
136 friend struct Node;
137 typedef typename allocator::pointer TPtr;
138 typedef typename allocator::size_type size_type;
139 typedef typename allocator::template rebind<Node>::other nallocator;
140 typedef typename nallocator::pointer NPtr;
141 struct Node
142 {
143 struct Edge
144 {
145 typedef typename allocator::pointer TPtr;
146 typedef typename allocator::template rebind<Node>::other nallocator;
147 typedef typename nallocator::pointer NPtr;
148 inline void construct(order_t k, height_t height, size_t *buf_size, allocator alloc, nallocator nalloc);
149 inline void destroy(allocator alloc, nallocator nalloc);
150 typename allocator::template rebind<Node>::other::pointer child;
151 typename allocator::pointer head, tail, begin, end;
152 private:
153 static inline void fill_dflt(TPtr b, TPtr e, allocator alloc);
154 } edges[order];
155 inline void construct(order_t k, height_t height, size_t *buf_size, allocator alloc, nallocator nalloc);
156 inline void destroy(allocator alloc, nallocator nalloc);
157 };
158 typedef std::pair<RanIt,RanIt> stream_t;
159 typedef typename allocator::template rebind<stream_t>::other sallocator;
160 typedef typename sallocator::pointer SPtr;
161public:
162 inline merge_tree(order_t k) : k(k), cold(true)
163 { construct(k); }
164 inline merge_tree(order_t k, const allocator& alloc) : k(k), cold(true), alloc(alloc), salloc(alloc), nalloc(alloc)
165 { construct(k); }
167
168 static inline order_t min_order()
169 { return order; }
170
171 class stream
172 {
173 private:
174 SPtr pair;
175 public:
176 stream(SPtr pair) : pair(pair) { }
177 inline RanIt& begin()
178 { return pair->first; }
179 inline RanIt& end()
180 { return pair->second; }
181 };
182 class stream_iterator
183 {
184 private:
185 SPtr ptr;
186 public:
187 stream_iterator(SPtr ptr) : ptr(ptr) { }
189 { return static_cast<order_t>(ptr-rhs.ptr); }
191 { return stream(ptr); }
193 { ++ptr; return *this; }
195 {
197 ++ptr;
198 return ret;
199 }
200 inline bool operator==(const stream_iterator& rhs)
201 { return ptr == rhs.ptr; }
202 inline bool operator!=(const stream_iterator& rhs)
203 { return ptr != rhs.ptr; }
204 };
205
206 inline void add_stream(RanIt begin, RanIt end)
207 { *last_stream++ = std::make_pair(begin,end); }
209 { return stream_iterator(input_streams); }
211 { return stream_iterator(last_stream); }
212 inline void reset();
213
214 inline void set_refiller(const Refiller& r)
215 { refiller = r; }
216 inline const Refiller& get_refiller() const
217 { return refiller; }
218 template<class FwIt>
219 inline FwIt empty(FwIt begin, FwIt end)
220 { return empty_buffers(root, begin, end); }
221 template<class OutIt>
222 inline OutIt empty(OutIt begin)
223 { return empty_buffers(root, begin); }
224
225 template<class It>
226 inline It operator()(It begin, It end);
227 template<class OutIt>
228 inline OutIt operator()(OutIt begin);
229
230private:
231 template<class FwIt>
232 static inline FwIt empty_buffers(NPtr n, FwIt begin, FwIt end);
233 template<class OutIt>
234 static inline OutIt empty_buffers(NPtr n, OutIt begin);
235
236 static void compute_buffer_sizes(size_type *b, size_type *e);
237 void construct(order_t k);
238
239 inline void go_down(typename Node::Edge& e, bfs_index<order> index);
240 inline void go_down_cold(typename Node::Edge& e, bfs_index<order>& index);
241
242 void warmup(NPtr n, typename Node::Edge& output, bfs_index<order> index);
243
244 template<class FwIt>
245 inline FwIt copy_root(typename Node::Edge& de, bfs_index<order> index, FwIt begin, FwIt end, std::forward_iterator_tag);
246 template<class RIt>
247 inline RIt copy_root(typename Node::Edge& de, bfs_index<order> index, RIt begin, RIt end, std::random_access_iterator_tag);
248 template<class OutIt>
249 inline OutIt copy_root(typename Node::Edge& de, bfs_index<order> index, OutIt begin);
250
251 inline TPtr copy(typename Node::Edge& de, bfs_index<order> index, TPtr b, TPtr e);
252
253 template<class FwIt>
254 inline FwIt fill_root(FwIt begin, FwIt end)
256 template<class OutIt>
257 inline OutIt fill_root(OutIt begin)
259 void fill(NPtr n, typename Node::Edge& output, bfs_index<order> index)
260 { special_<RanIt,order,Splitter,Pred,Refiller,Alloc>::fill(this, n, output, index); }
261 void fill_leaf(typename Node::Edge& output, bfs_index<order> index)
262 { special_<RanIt,order,Splitter,Pred,Refiller,Alloc>::fill_leaf(this, output, index); }
263
264private:
265 order_t k;
266 order_t leaf_index;
267 bool cold;
268 NPtr root;
269 SPtr input_streams, last_stream;
270 Pred comp;
271 allocator alloc;
272 sallocator salloc;
273 nallocator nalloc;
274 Refiller refiller;
275};
276
277
278
279/*****
280 * Alloc::pointer iterator template specialization
281 */
282
283template<int Order, class Splitter, class Pred, class Refiller, class Alloc>
284class merge_tree<typename Alloc::pointer, Order, Splitter, Pred, Refiller, Alloc>
285{
286 typedef typename Alloc::pointer RanIt;
287 friend class special_<typename Alloc::pointer,Order,Splitter,Pred,Refiller,Alloc>;
288public:
289 typedef unsigned int order_t;
290 enum order_tag_ { order = Order };
292 typedef Splitter splitter;
293 typedef typename std::iterator_traits<typename Alloc::pointer>::value_type value_type;
294 typedef Alloc allocator;
295 typedef typename Alloc::pointer iterator;
296 typedef Pred predicate;
297// template<class NewRefiller>
298// struct rebind { typedef merge_tree<typename Alloc::pointer, Order, Splitter, Pred, NewRefiller, Alloc> other; };
299private:
300 struct Node;
301 friend struct Node;
302 typedef typename allocator::pointer TPtr;
303 typedef typename allocator::size_type size_type;
304 typedef typename allocator::template rebind<Node>::other nallocator;
305 typedef typename nallocator::pointer NPtr;
306 struct Node
307 {
308 struct Edge
309 {
310 typedef typename allocator::pointer TPtr;
311 typedef typename allocator::template rebind<Node>::other nallocator;
312 typedef typename nallocator::pointer NPtr;
313 inline Edge** construct(order_t k, height_t height, size_t *buf_size, Edge** edge_list, allocator alloc, nallocator nalloc);
314 inline void destroy(allocator alloc, nallocator nalloc);
315 typename nallocator::pointer child;
316 typename allocator::pointer head, tail, begin, end;
317 private:
318 static inline void fill_dflt(TPtr b, TPtr e, allocator alloc);
319 } edges[order];
320 inline Edge** construct(order_t k, height_t height, size_t *buf_size, Edge** edge_list, allocator alloc, nallocator nalloc);
321 inline void destroy(allocator alloc, nallocator nalloc);
322 };
323 typedef typename Node::Edge* stream_t;
324 typedef typename allocator::template rebind<stream_t>::other sallocator;
325 typedef typename sallocator::pointer SPtr;
326public:
327 inline merge_tree(order_t k) : k(k), cold(true)
328 { construct(k); }
329 inline merge_tree(order_t k, const allocator& alloc) : k(k), cold(true), alloc(alloc), salloc(alloc), nalloc(alloc)
330 { construct(k); }
332
333 static inline order_t min_order()
334 { return order; }
335
336 class stream
337 {
338 private:
339 stream_t edge;
340 public:
341 inline stream(stream_t edge) : edge(edge) { }
342 inline typename allocator::pointer& begin()
343 { return edge->head; }
344 inline typename allocator::pointer& end()
345 { return edge->tail; }
346 };
347 class stream_iterator
348 {
349 private:
350 SPtr ptr;
351 public:
352 inline stream_iterator(SPtr ptr) : ptr(ptr) { }
353 inline order_t operator-(const stream_iterator& rhs)
354 { return static_cast<order_t>(ptr-rhs.ptr); }
355 inline stream operator*()
356 { return stream(*ptr); }
357 inline stream_iterator& operator++()
358 { ++ptr; return *this; }
359 inline stream_iterator& operator++(int)
360 {
361 stream_iterator ret = stream_iterator(ptr);
362 ++ptr;
363 return ret;
364 }
365 inline bool operator==(const stream_iterator& rhs)
366 { return ptr == rhs.ptr; }
367 inline bool operator!=(const stream_iterator& rhs)
368 { return ptr != rhs.ptr; }
369 };
370
371 inline void add_stream(typename Alloc::pointer begin, typename Alloc::pointer end)
372 { (*last_stream)->head = begin, (*last_stream)->tail = end, ++last_stream; }
373 inline stream_iterator begin()
374 { return input_streams; }
375 inline stream_iterator end()
376 { return last_stream; }
377 inline void reset();
378
379 inline void set_refiller(const Refiller& r)
380 { refiller = r; }
381 inline const Refiller& get_refiller() const
382 { return refiller; }
383 template<class FwIt>
384 inline FwIt empty(FwIt begin, FwIt end)
385 { return empty_buffers(root, begin, end); }
386 template<class OutIt>
387 inline OutIt empty(OutIt begin)
388 { return empty_buffers(root, begin); }
389
390 template<class FwIt>
391 inline FwIt operator()(FwIt begin, FwIt end);
392 template<class OutIt>
393 inline OutIt operator()(OutIt begin);
394private:
395 template<class FwIt>
396 static inline FwIt empty_buffers(NPtr n, FwIt begin, FwIt end);
397 template<class OutIt>
398 static inline OutIt empty_buffers(NPtr n, OutIt begin);
399
400 void construct(order_t k);
401 static void compute_buffer_sizes(size_type *b, size_type *e);
402
403 static inline void go_down(typename Node::Edge& e, Pred comp);
404 static inline void go_down_cold(typename Node::Edge& e, Pred comp);
405
406 static void warmup(NPtr n, typename Node::Edge& output, Pred comp);
407
408 template<class OutIt>
409 static inline OutIt copy(typename Node::Edge& de, OutIt begin, Pred comp);
410 template<class FwIt>
411 static inline FwIt copy(typename Node::Edge& de, FwIt begin, FwIt end, Pred comp, std::forward_iterator_tag);
412 template<class RIt>
413 static inline RIt copy(typename Node::Edge& de, RIt begin, RIt end, Pred comp, std::random_access_iterator_tag);
414
415 template<class OutIt>
416 static inline OutIt fill(NPtr n, OutIt begin, Pred comp)
418 template<class FwIt>
419 static inline FwIt fill(NPtr n, FwIt begin, FwIt end, Pred comp)
421private:
422 order_t k;
423 order_t leaf_index;
424 bool cold;
425 NPtr root;
426 SPtr input_streams, last_stream;
427 Pred comp;
428 allocator alloc;
429 sallocator salloc;
430 nallocator nalloc;
431 Refiller refiller;
432};
433
434} // namespace iosort
435
436#include "funnel.timpl.h"
437#endif // FUNNEL_H_INCLUDED__
void child(basic_order_t ch)
Definition funnel.h:83
bfs_index< order > operator=(const bfs_index< order > &rhs)
Definition funnel.h:77
bool operator!=(const bfs_index< order > &rhs) const
Definition funnel.h:81
basic_order_t child_index() const
Definition funnel.h:87
bool operator==(const bfs_index< order > &rhs) const
Definition funnel.h:79
void parent()
Definition funnel.h:85
static order_t prefered_order_input(diff_type N)
Definition funnel.h:102
static height_t split(height_t h)
Definition funnel.h:106
static order_t prefered_order_output(diff_type N)
Definition funnel.h:99
static size_t out_buffer_size(order_t k)
Definition funnel.h:108
static size_t switch_to_cache_aware()
Definition funnel.h:104
bool operator==(const stream_iterator &rhs)
Definition funnel.h:200
stream_iterator & operator++(int)
Definition funnel.h:194
stream_iterator & operator++()
Definition funnel.h:192
order_t operator-(const stream_iterator &rhs)
Definition funnel.h:188
bool operator!=(const stream_iterator &rhs)
Definition funnel.h:202
void add_stream(typename Alloc::pointer begin, typename Alloc::pointer end)
Definition funnel.h:371
std::iterator_traits< typenameAlloc::pointer >::value_type value_type
Definition funnel.h:293
const Refiller & get_refiller() const
Definition funnel.h:216
It operator()(It begin, It end)
OutIt empty(OutIt begin)
Definition funnel.h:222
merge_tree(order_t k, const allocator &alloc)
Definition funnel.h:164
FwIt empty(FwIt begin, FwIt end)
Definition funnel.h:219
void add_stream(RanIt begin, RanIt end)
Definition funnel.h:206
Splitter splitter
Definition funnel.h:127
static order_t min_order()
Definition funnel.h:168
void set_refiller(const Refiller &r)
Definition funnel.h:214
stream_iterator begin()
Definition funnel.h:208
merge_tree(order_t k)
Definition funnel.h:162
unsigned int order_t
Definition funnel.h:124
std::iterator_traits< RanIt >::value_type value_type
Definition funnel.h:128
stream_iterator end()
Definition funnel.h:210
OutIt operator()(OutIt begin)
friend struct Node
Definition funnel.h:136
bool output
Definition comms.cpp:56
height_t logc(order_t k)
Definition funnel.h:37
unsigned int order_t
Definition funnel.h:34
order_t pow_of_order< 16 >(height_t h)
Definition funnel.h:67
order_t pow_of_order< 8 >(height_t h)
Definition funnel.h:64
unsigned short basic_order_t
Definition funnel.h:33
order_t pow_of_order< 2 >(height_t h)
Definition funnel.h:58
order_t pow_of_order< 4 >(height_t h)
Definition funnel.h:61
order_t pow_of_order(height_t h)
Definition funnel.h:51
unsigned short height_t
Definition funnel.h:32
Definition Node.h:14
allocator::template rebind< Node >::other::pointer child
Definition funnel.h:150
allocator::pointer TPtr
Definition funnel.h:145
void construct(order_t k, height_t height, size_t *buf_size, allocator alloc, nallocator nalloc)
nallocator::pointer NPtr
Definition funnel.h:147
allocator::pointer tail
Definition funnel.h:151
void destroy(allocator alloc, nallocator nalloc)
allocator::pointer begin
Definition funnel.h:151
allocator::template rebind< Node >::other nallocator
Definition funnel.h:146
allocator::pointer head
Definition funnel.h:151
allocator::pointer end
Definition funnel.h:151
merge_tree< iterator, order, splitter, predicate, NewRefiller, allocator > other
Definition funnel.h:133
Edge ** construct(order_t k, height_t height, size_t *buf_size, Edge **edge_list, allocator alloc, nallocator nalloc)
bool operator()(const Merger *, FwIt, FwIt)
Definition funnel.h:112