Stxxl
1.4.0
|
00001 /*************************************************************************** 00002 * include/stxxl/bits/containers/sorter.h 00003 * 00004 * Part of the STXXL. See http://stxxl.sourceforge.net 00005 * 00006 * Copyright (C) 2012 Timo Bingmann <bingmann@kit.edu> 00007 * 00008 * Distributed under the Boost Software License, Version 1.0. 00009 * (See accompanying file LICENSE_1_0.txt or copy at 00010 * http://www.boost.org/LICENSE_1_0.txt) 00011 **************************************************************************/ 00012 00013 #ifndef STXXL_SORTER_HEADER 00014 #define STXXL_SORTER_HEADER 00015 00016 #include <stxxl/bits/deprecated.h> 00017 #include <stxxl/bits/stream/sort_stream.h> 00018 00019 __STXXL_BEGIN_NAMESPACE 00020 00021 #ifndef STXXL_VERBOSE_SORTER 00022 #define STXXL_VERBOSE_SORTER STXXL_VERBOSE2 00023 #endif 00024 00025 //! \addtogroup stlcont 00026 //! \{ 00027 00028 /** 00029 * \brief External Sorter: use stream package objects to keep a sorted container. 00030 * 00031 * This sorter container combines the two functions of runs_creator and 00032 * runs_merger from the stream packages into a two-phase container. 00033 * 00034 * In the first phase the container is filled with unordered items via push(), 00035 * which are presorted internally into runs of size M. When the internal memory 00036 * overflows a runs is written to external memory in blocks of block_size. 00037 * 00038 * When sort() is called the container enters the output phase and push() is 00039 * disallowed. After calling sort() the items can be read in sorted order using 00040 * operator*() to get the top item, operator++() to advance to the next one and 00041 * empty() to check for end of stream. This is exactly the stream interface. 00042 * 00043 * In the output phase the sorter can be returned to the beginning of the 00044 * stream using rewind() and everything is read again in sorted order. 00045 * 00046 * Using clear() the object can be reset into input state and all items are 00047 * destroyed. 00048 * 00049 * \tparam ValueType type of the contained objects (POD with no references to internal memory) 00050 * \tparam CompareType type of comparison object used for sorting the runs 00051 * \tparam BlockSize size of the external memory block in bytes, default is \c STXXL_DEFAULT_BLOCK_SIZE(ValTp) 00052 * \tparam AllocStr parallel disk allocation strategy, default is \c STXXL_DEFAULT_ALLOC_STRATEGY 00053 */ 00054 template <typename ValueType, 00055 typename CompareType, 00056 unsigned BlockSize = STXXL_DEFAULT_BLOCK_SIZE(ValueType), 00057 class AllocStrategy = STXXL_DEFAULT_ALLOC_STRATEGY> 00058 class sorter : private noncopyable 00059 { 00060 public: 00061 // *** Template Parameters 00062 00063 typedef ValueType value_type; 00064 typedef CompareType cmp_type; 00065 enum { 00066 block_size = BlockSize 00067 }; 00068 typedef AllocStrategy alloc_strategy_type; 00069 00070 // *** Constructed Types 00071 00072 /// runs creator type with push() method 00073 typedef stream::runs_creator< stream::use_push<ValueType>, cmp_type, 00074 block_size, alloc_strategy_type > runs_creator_type; 00075 00076 /// corresponding runs merger type 00077 typedef stream::runs_merger< typename runs_creator_type::sorted_runs_type, 00078 cmp_type, alloc_strategy_type > runs_merger_type; 00079 00080 protected: 00081 00082 // *** Object Attributes 00083 00084 /// current state of sorter 00085 enum { STATE_INPUT, STATE_OUTPUT } m_state; 00086 00087 // runs creator object holding all items 00088 runs_creator_type m_runs_creator; 00089 00090 // runs merger reading items when in STATE_OUTPUT 00091 runs_merger_type m_runs_merger; 00092 00093 public: 00094 00095 //! Constructor allocation memory_to_use bytes in ram for sorted runs. 00096 sorter(const cmp_type& cmp, unsigned_type memory_to_use) 00097 : m_state(STATE_INPUT), 00098 m_runs_creator(cmp, memory_to_use), 00099 m_runs_merger(cmp, memory_to_use) 00100 { 00101 } 00102 00103 // Constructor variant with differently sizes runs_creator and runs_merger 00104 sorter(const cmp_type& cmp, unsigned_type creator_memory_to_use, unsigned_type merger_memory_to_use) 00105 : m_state(STATE_INPUT), 00106 m_runs_creator(cmp, creator_memory_to_use), 00107 m_runs_merger(cmp, merger_memory_to_use) 00108 { 00109 } 00110 00111 //! Remove all items and return to input state. 00112 void clear() 00113 { 00114 if ( m_state == STATE_OUTPUT ) 00115 m_runs_merger.deallocate(); 00116 00117 m_runs_creator.allocate(); 00118 m_state = STATE_INPUT; 00119 } 00120 00121 //! Push another item (only callable during input state). 00122 void push(const value_type & val) 00123 { 00124 assert( m_state == STATE_INPUT ); 00125 m_runs_creator.push(val); 00126 } 00127 00128 //! Finish push input state and deallocate input buffer. 00129 void finish() 00130 { 00131 if (m_state == STATE_OUTPUT) 00132 { 00133 m_runs_merger.deallocate(); 00134 } 00135 00136 m_runs_creator.deallocate(); 00137 } 00138 00139 //! Deallocate buffers and clear result. 00140 void finish_clear() 00141 { 00142 if (m_state == STATE_OUTPUT) 00143 { 00144 m_runs_merger.deallocate(); 00145 m_runs_creator.result()->clear(); 00146 } 00147 00148 m_runs_creator.deallocate(); 00149 } 00150 00151 //! Number of items pushed or items remaining to be read. 00152 unsigned_type size() const 00153 { 00154 if ( m_state == STATE_INPUT ) 00155 return m_runs_creator.size(); 00156 else 00157 return m_runs_merger.size(); 00158 } 00159 00160 //! Switch to output state, rewind() in case the output was already sorted. 00161 void sort() 00162 { 00163 if (m_state == STATE_OUTPUT) 00164 { 00165 m_runs_merger.deallocate(); 00166 } 00167 00168 m_runs_creator.deallocate(); 00169 m_runs_merger.initialize(m_runs_creator.result()); 00170 m_state = STATE_OUTPUT; 00171 } 00172 00173 //! Switch to output state, rewind() in case the output was already sorted. 00174 void sort(unsigned_type merger_memory_to_use) 00175 { 00176 m_runs_merger.set_memory_to_use(merger_memory_to_use); 00177 sort(); 00178 } 00179 00180 //! Switch to output state, rewind() in case the output was already sorted. 00181 void sort_reuse() 00182 { 00183 assert( m_state == STATE_INPUT ); 00184 00185 m_runs_merger.initialize(m_runs_creator.result()); 00186 m_state = STATE_OUTPUT; 00187 } 00188 00189 //! Rewind output stream to beginning. 00190 void rewind() 00191 { 00192 assert( m_state == STATE_OUTPUT ); 00193 00194 m_runs_merger.deallocate(); 00195 00196 m_state = STATE_INPUT; 00197 return sort(); 00198 } 00199 00200 //! Change runs_creator memory usage 00201 void set_creator_memory_to_use(unsigned_type creator_memory_to_use) 00202 { 00203 m_runs_creator.set_memory_to_use(creator_memory_to_use); 00204 } 00205 00206 //! Change runs_merger memory usage 00207 void set_merger_memory_to_use(unsigned_type merger_memory_to_use) 00208 { 00209 m_runs_merger.set_memory_to_use(merger_memory_to_use); 00210 } 00211 00212 //! \brief Standard stream method 00213 bool empty() const 00214 { 00215 assert( m_state == STATE_OUTPUT ); 00216 return m_runs_merger.empty(); 00217 } 00218 00219 //! \brief Standard stream method 00220 const value_type& operator * () const 00221 { 00222 assert( m_state == STATE_OUTPUT ); 00223 return *m_runs_merger; 00224 } 00225 00226 //! \brief Standard stream method 00227 const value_type* operator -> () const 00228 { 00229 return &(operator * ()); 00230 } 00231 00232 //! \brief Standard stream method (preincrement operator) 00233 sorter& operator ++ () 00234 { 00235 assert( m_state == STATE_OUTPUT ); 00236 ++m_runs_merger; 00237 return *this; 00238 } 00239 }; 00240 00241 //! \} 00242 00243 __STXXL_END_NAMESPACE 00244 00245 #endif // !STXXL_SORTER_HEADER 00246 // vim: et:ts=4:sw=4