Stxxl  1.4.0
include/stxxl/bits/containers/sorter.h
Go to the documentation of this file.
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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines