Stxxl  1.4.0
include/stxxl/bits/containers/deque2.h
Go to the documentation of this file.
00001 /***************************************************************************
00002  *  include/stxxl/bits/containers/deque2.h
00003  *
00004  *  Part of the STXXL. See http://stxxl.sourceforge.net
00005  *
00006  *  Copyright (C) 2012 Timo Bingmann <bingmann@kit.edu>
00007  *  based on include/stxxl/bits/containers/queue.h
00008  *
00009  *  Distributed under the Boost Software License, Version 1.0.
00010  *  (See accompanying file LICENSE_1_0.txt or copy at
00011  *  http://www.boost.org/LICENSE_1_0.txt)
00012  **************************************************************************/
00013 
00014 #ifndef STXXL_DEQUE2_HEADER
00015 #define STXXL_DEQUE2_HEADER
00016 
00017 #include <deque>
00018 
00019 #include <stxxl/bits/deprecated.h>
00020 #include <stxxl/bits/mng/mng.h>
00021 #include <stxxl/bits/mng/typed_block.h>
00022 #include <stxxl/bits/common/tmeta.h>
00023 #include <stxxl/bits/mng/read_write_pool.h>
00024 #include <stxxl/bits/mng/write_pool.h>
00025 #include <stxxl/bits/mng/prefetch_pool.h>
00026 
00027 
00028 __STXXL_BEGIN_NAMESPACE
00029 
00030 #ifndef STXXL_VERBOSE_DEQUE2
00031 #define STXXL_VERBOSE_DEQUE2 STXXL_VERBOSE2
00032 #endif
00033 
00034 //! \addtogroup stlcont
00035 //! \{
00036 
00037 //! \brief External deque container without random access
00038 
00039 //! \tparam ValueType type of the contained objects (POD with no references to internal memory)
00040 //! \tparam BlockSize size of the external memory block in bytes, default is \c STXXL_DEFAULT_BLOCK_SIZE(ValTp)
00041 //! \tparam AllocStrategy parallel disk allocation strategy, default is \c STXXL_DEFAULT_ALLOC_STRATEGY
00042 //! \tparam SizeType size data type, default is \c stxxl::uint64
00043 template <class ValueType,
00044           unsigned BlockSize = STXXL_DEFAULT_BLOCK_SIZE(ValueType),
00045           class AllocStrategy = STXXL_DEFAULT_ALLOC_STRATEGY,
00046           class SizeType = stxxl::uint64>
00047 class deque2 : private noncopyable
00048 {
00049 public:
00050     typedef ValueType value_type;
00051     typedef AllocStrategy alloc_strategy_type;
00052     typedef SizeType size_type;
00053     enum {
00054         block_size = BlockSize
00055     };
00056 
00057     typedef typed_block<block_size, value_type> block_type;
00058     typedef BID<block_size> bid_type;
00059 
00060     typedef std::deque<bid_type> bid_deque_type;
00061 
00062 private:
00063     typedef read_write_pool<block_type> pool_type;
00064 
00065     /// current number of items in the deque
00066     size_type m_size;
00067 
00068     /// whether the m_pool object is own and should be deleted.
00069     bool m_owns_pool;
00070 
00071     /// read_write_pool of blocks
00072     pool_type* m_pool;
00073 
00074     /// current front block of deque
00075     block_type* m_front_block;
00076 
00077     /// current back block of deque
00078     block_type* m_back_block;
00079 
00080     /// pointer to current front element in m_front_block
00081     value_type * m_front_element;
00082 
00083     /// pointer to current back element in m_back_block
00084     value_type * m_back_element;
00085 
00086     /// block allocation strategy
00087     alloc_strategy_type m_alloc_strategy;
00088 
00089     /// block allocation counter
00090     unsigned_type m_alloc_count;
00091 
00092     /// allocated block identifiers
00093     bid_deque_type m_bids;
00094 
00095     /// block manager used
00096     block_manager* m_bm;
00097 
00098     /// number of blocks to prefetch
00099     unsigned_type m_blocks2prefetch;
00100 
00101 public:
00102     //! \brief Constructs empty deque with own write and prefetch block pool
00103 
00104     //! \param D  number of parallel disks, defaulting to the configured number of scratch disks,
00105     //!           memory consumption will be 2 * D + 2 blocks 
00106     //!           (first and last block, D blocks as write cache, D block for prefetching)
00107     explicit deque2(int D = -1) :
00108         m_size(0),
00109         m_owns_pool(true),
00110         m_alloc_count(0),
00111         m_bm(block_manager::get_instance())
00112     {
00113         if (D < 1) D = config::get_instance()->disks_number();
00114         STXXL_VERBOSE_DEQUE2("deque2[" << this << "]::deque2(D)");
00115         m_pool = new pool_type(D, D + 2);
00116         init();
00117     }
00118 
00119     //! \brief Constructs empty deque2 with own write and prefetch block pool
00120 
00121     //! \param w_pool_size  number of blocks in the write pool, must be at least 2, recommended at least 3
00122     //! \param p_pool_size  number of blocks in the prefetch pool, recommended at least 1
00123     //! \param blocks2prefetch  defines the number of blocks to prefetch (\c front side),
00124     //!                          default is number of block in the prefetch pool
00125     explicit deque2(unsigned_type w_pool_size, unsigned_type p_pool_size, int blocks2prefetch = -1) :
00126         m_size(0),
00127         m_owns_pool(true),
00128         m_alloc_count(0),
00129         m_bm(block_manager::get_instance())
00130     {
00131         STXXL_VERBOSE_DEQUE2("deque2[" << this << "]::deque2(sizes)");
00132         m_pool = new pool_type(p_pool_size, w_pool_size);
00133         init(blocks2prefetch);
00134     }
00135 
00136     //! \brief Constructs empty deque
00137 
00138     //! \param pool_ block write/prefetch pool
00139     //! \param blocks2prefetch  defines the number of blocks to prefetch (\c front side),
00140     //!                          default is number of blocks in the prefetch pool
00141     //!  \warning Number of blocks in the write pool must be at least 2, recommended at least 3
00142     //!  \warning Number of blocks in the prefetch pool recommended at least 1
00143     deque2(pool_type & pool, int blocks2prefetch = -1) :
00144         m_size(0),
00145         m_owns_pool(false),
00146         m_pool(&pool),
00147         m_alloc_count(0),
00148         m_bm(block_manager::get_instance())
00149     {
00150         STXXL_VERBOSE_DEQUE2("deque2[" << this << "]::deque2(pool)");
00151         init(blocks2prefetch);
00152     }
00153 
00154     void swap(deque2& obj)
00155     {
00156         std::swap(m_size, obj.m_size);
00157         std::swap(m_owns_pool, obj.m_owns_pool);
00158         std::swap(m_pool, obj.m_pool);
00159         std::swap(m_front_block, obj.m_front_block);
00160         std::swap(m_back_block, obj.m_back_block);
00161         std::swap(m_front_element, obj.m_front_element);
00162         std::swap(m_back_element, obj.m_back_element);
00163         std::swap(m_alloc_strategy, obj.m_alloc_strategy);
00164         std::swap(m_alloc_count, obj.m_alloc_count);
00165         std::swap(m_bids, obj.m_bids);
00166         std::swap(m_bm, obj.m_bm);
00167         std::swap(m_blocks2prefetch, obj.m_blocks2prefetch);
00168     }
00169 
00170 private:
00171     void init(int blocks2prefetch = -1)
00172     {
00173         if (m_pool->size_write() < 2) {
00174             STXXL_ERRMSG("deque2: invalid configuration, not enough blocks (" << m_pool->size_write() <<
00175                          ") in write pool, at least 2 are needed, resizing to 3");
00176             m_pool->resize_write(3);
00177         }
00178 
00179         if (m_pool->size_write() < 3) {
00180             STXXL_MSG("deque2: inefficient configuration, no blocks for buffered writing available");
00181         }
00182 
00183         if (m_pool->size_prefetch() < 1) {
00184             STXXL_MSG("deque2: inefficient configuration, no blocks for prefetching available");
00185         }
00186 
00187         /// initialize empty deque
00188         m_front_block = m_back_block = m_pool->steal();
00189         m_back_element = m_back_block->begin() - 1;
00190         m_front_element = m_back_block->begin();
00191         set_prefetch_aggr(blocks2prefetch);
00192     }
00193 
00194 public:
00195     //! \brief Defines the number of blocks to prefetch (\c front side)
00196     //!        This method should be called whenever the prefetch pool is resized
00197     //! \param blocks2prefetch  defines the number of blocks to prefetch (\c front side),
00198     //!                         a negative value means to use the number of blocks in the prefetch pool
00199     void set_prefetch_aggr(int_type blocks2prefetch)
00200     {
00201         if (blocks2prefetch < 0)
00202             m_blocks2prefetch = m_pool->size_prefetch();
00203         else
00204             m_blocks2prefetch = blocks2prefetch;
00205     }
00206 
00207     //! \brief Returns the number of blocks prefetched from the \c front side
00208     unsigned_type get_prefetch_aggr() const
00209     {
00210         return m_blocks2prefetch;
00211     }
00212 
00213     //! \brief Adds an element to the front of the deque
00214     void push_front(const value_type & val)
00215     {
00216         if (UNLIKELY(m_front_element == m_front_block->begin()))
00217         {
00218             if (m_size == 0)
00219             {
00220                 STXXL_VERBOSE1("deque2::push_front Case 0");
00221                 assert(m_front_block == m_back_block);
00222                 m_front_element = m_back_element = m_front_block->end()-1;
00223                 *m_front_element = val;
00224                 ++m_size;
00225                 return;
00226             }
00227             // front block is completely filled
00228             else if (m_front_block == m_back_block)
00229             {
00230                 // can not write the front block because it
00231                 // is the same as the back block, must keep it memory
00232                 STXXL_VERBOSE1("deque2::push_front Case 1");
00233             }
00234             else if (size() < 2 * block_type::size)
00235             {
00236                 STXXL_VERBOSE1("deque2::push_front Case 1.5");
00237                 // only two blocks with a gap at the end, move elements within memory
00238                 assert(m_bids.empty());
00239                 size_t gap = m_back_block->end() - (m_back_element+1);
00240                 assert(gap > 0);
00241                 std::copy_backward(m_back_block->begin(), m_back_element+1, m_back_block->end());
00242                 std::copy_backward(m_front_block->end() - gap, m_front_block->end(), m_back_block->begin() + gap);
00243                 std::copy_backward(m_front_block->begin(), m_front_block->end() - gap, m_front_block->end());
00244                 m_front_element += gap;
00245                 m_back_element += gap;
00246 
00247                 --m_front_element;
00248                 *m_front_element = val;
00249                 ++m_size;
00250                 return;
00251             }
00252             else
00253             {
00254                 STXXL_VERBOSE1("deque2::push_front Case 2");
00255                 // write the front block
00256                 // need to allocate new block
00257                 bid_type newbid;
00258 
00259                 m_bm->new_block(m_alloc_strategy, newbid, m_alloc_count++);
00260 
00261                 STXXL_VERBOSE_DEQUE2("deque2[" << this << "]: push_front block " << m_front_block << " @ " << FMT_BID(newbid));
00262                 m_bids.push_front(newbid);
00263                 m_pool->write(m_front_block, newbid);
00264                 if (m_bids.size() <= m_blocks2prefetch) {
00265                     STXXL_VERBOSE1("deque2::push Case Hints");
00266                     m_pool->hint(newbid);
00267                 }
00268             }
00269 
00270             m_front_block = m_pool->steal();
00271             m_front_element = m_front_block->end()-1;
00272             *m_front_element = val;
00273             ++m_size;
00274         }
00275         else // not at beginning of a block
00276         {
00277             --m_front_element;
00278             *m_front_element = val;
00279             ++m_size;
00280         }
00281     }
00282 
00283     //! \brief Adds an element to the end of the deque
00284     void push_back(const value_type & val)
00285     {
00286         if (UNLIKELY(m_back_element == m_back_block->begin() + (block_type::size - 1)))
00287         {
00288             // back block is completely  filled
00289             if (m_front_block == m_back_block)
00290             {
00291                 // can not write the back block because it
00292                 // is the same as the front block, must keep it memory
00293                 STXXL_VERBOSE1("deque2::push_back Case 1");
00294             }
00295             else if (size() < 2 * block_type::size)
00296             {
00297                 STXXL_VERBOSE1("deque2::push_back Case 1.5");
00298                 // only two blocks with a gap in the beginning, move elements within memory
00299                 assert(m_bids.empty());
00300                 size_t gap = m_front_element - m_front_block->begin();
00301                 assert(gap > 0);
00302                 std::copy(m_front_element, m_front_block->end(), m_front_block->begin());
00303                 std::copy(m_back_block->begin(), m_back_block->begin() + gap, m_front_block->begin() + (block_type::size - gap));
00304                 std::copy(m_back_block->begin() + gap, m_back_block->end(), m_back_block->begin());
00305                 m_front_element -= gap;
00306                 m_back_element -= gap;
00307 
00308                 ++m_back_element;
00309                 *m_back_element = val;
00310                 ++m_size;
00311                 return;
00312             }
00313             else
00314             {
00315                 STXXL_VERBOSE1("deque2::push_back Case 2");
00316                 // write the back block
00317                 // need to allocate new block
00318                 bid_type newbid;
00319 
00320                 m_bm->new_block(m_alloc_strategy, newbid, m_alloc_count++);
00321 
00322                 STXXL_VERBOSE_DEQUE2("deque2[" << this << "]: push_back block " << m_back_block << " @ " << FMT_BID(newbid));
00323                 m_bids.push_back(newbid);
00324                 m_pool->write(m_back_block, newbid);
00325                 if (m_bids.size() <= m_blocks2prefetch) {
00326                     STXXL_VERBOSE1("deque2::push_back Case Hints");
00327                     m_pool->hint(newbid);
00328                 }
00329             }
00330             m_back_block = m_pool->steal();
00331 
00332             m_back_element = m_back_block->begin();
00333             *m_back_element = val;
00334             ++m_size;
00335         }
00336         else // not at end of a block
00337         {
00338             ++m_back_element;
00339             *m_back_element = val;
00340             ++m_size;
00341         }
00342     }
00343 
00344     //! \brief Removes element from the front of the deque
00345     void pop_front()
00346     {
00347         assert(!empty());
00348 
00349         if (UNLIKELY(m_front_element == m_front_block->begin() + (block_type::size - 1)))
00350         {
00351             // if there is only one block, it implies ...
00352             if (m_back_block == m_front_block)
00353             {
00354                 STXXL_VERBOSE1("deque2::pop_front Case 1");
00355                 assert(size() == 1);
00356                 assert(m_back_element == m_front_element);
00357                 assert(m_bids.empty());
00358                 // reset everything
00359                 m_back_element = m_back_block->begin() - 1;
00360                 m_front_element = m_back_block->begin();
00361                 m_size = 0;
00362                 return;
00363             }
00364 
00365             --m_size;
00366             if (m_size <= block_type::size)
00367             {
00368                 STXXL_VERBOSE1("deque2::pop_front Case 2");
00369                 assert(m_bids.empty());
00370                 // the m_back_block is the next block
00371                 m_pool->add(m_front_block);
00372                 m_front_block = m_back_block;
00373                 m_front_element = m_back_block->begin();
00374                 return;
00375             }
00376             STXXL_VERBOSE1("deque2::pop_front Case 3");
00377 
00378             assert(!m_bids.empty());
00379             request_ptr req = m_pool->read(m_front_block, m_bids.front());
00380             STXXL_VERBOSE_DEQUE2("deque2[" << this << "]: pop_front block  " << m_front_block << " @ " << FMT_BID(m_bids.front()));
00381 
00382             // give prefetching hints
00383             for (unsigned_type i = 0; i < m_blocks2prefetch && i < m_bids.size() - 1; ++i)
00384             {
00385                 STXXL_VERBOSE1("deque2::pop_front Case Hints");
00386                 m_pool->hint(m_bids[i + 1]);
00387             }
00388 
00389             m_front_element = m_front_block->begin();
00390             req->wait();
00391 
00392             m_bm->delete_block(m_bids.front());
00393             m_bids.pop_front();
00394         }
00395         else
00396         {
00397             ++m_front_element;
00398             --m_size;
00399         }
00400     }
00401 
00402     //! \brief Removes element from the back of the deque
00403     void pop_back()
00404     {
00405         assert(!empty());
00406 
00407         if (UNLIKELY(m_back_element == m_back_block->begin()))
00408         {
00409             // if there is only one block, it implies ...
00410             if (m_back_block == m_front_block)
00411             {
00412                 STXXL_VERBOSE1("deque2::pop_back Case 1");
00413                 assert(size() == 1);
00414                 assert(m_back_element == m_front_element);
00415                 assert(m_bids.empty());
00416                 // reset everything
00417                 m_back_element = m_back_block->begin() - 1;
00418                 m_front_element = m_back_block->begin();
00419                 m_size = 0;
00420                 return;
00421             }
00422 
00423             --m_size;
00424             if (m_size <= block_type::size)
00425             {
00426                 STXXL_VERBOSE1("deque2::pop_back Case 2");
00427                 assert(m_bids.empty());
00428                 // the m_front_block is the next block
00429                 m_pool->add(m_back_block);
00430                 m_back_block = m_front_block;
00431                 m_back_element = m_back_block->end() - 1;
00432                 return;
00433             }
00434 
00435             STXXL_VERBOSE1("deque2::pop_back Case 3");
00436 
00437             assert(!m_bids.empty());
00438             request_ptr req = m_pool->read(m_back_block, m_bids.back());
00439             STXXL_VERBOSE_DEQUE2("deque2[" << this << "]: pop_back block  " << m_back_block << " @ " << FMT_BID(m_bids.back()));
00440 
00441             // give prefetching hints
00442             for (unsigned_type i = 1; i < m_blocks2prefetch && i < m_bids.size() - 1; ++i)
00443             {
00444                 STXXL_VERBOSE1("deque2::pop_front Case Hints");
00445                 m_pool->hint(m_bids[m_bids.size()-1 - i]);
00446             }
00447 
00448             m_back_element = m_back_block->end() - 1;
00449             req->wait();
00450 
00451             m_bm->delete_block(m_bids.back());
00452             m_bids.pop_back();
00453         }
00454         else
00455         {
00456             --m_back_element;
00457             --m_size;
00458         }
00459     }
00460 
00461     //! \brief Returns the size of the deque
00462     size_type size() const
00463     {
00464         return m_size;
00465     }
00466 
00467     //! \brief Returns \c true if deque is empty
00468     bool empty() const
00469     {
00470         return (m_size == 0);
00471     }
00472 
00473     //! \brief Returns a mutable reference at the back of the deque
00474     value_type & back()
00475     {
00476         assert(!empty());
00477         return *m_back_element;
00478     }
00479 
00480     //! \brief Returns a const reference at the back of the deque
00481     const value_type & back() const
00482     {
00483         assert(!empty());
00484         return *m_back_element;
00485     }
00486 
00487     //! \brief Returns a mutable reference at the front of the deque
00488     value_type & front()
00489     {
00490         assert(!empty());
00491         return *m_front_element;
00492     }
00493 
00494     //! \brief Returns a const reference at the front of the deque
00495     const value_type & front() const
00496     {
00497         assert(!empty());
00498         return *m_front_element;
00499     }
00500 
00501     ~deque2()
00502     {
00503         if (m_front_block != m_back_block)
00504             m_pool->add(m_back_block);
00505 
00506         m_pool->add(m_front_block);
00507 
00508         if (m_owns_pool)
00509             delete m_pool;
00510 
00511         if (!m_bids.empty())
00512             m_bm->delete_blocks(m_bids.begin(), m_bids.end());
00513     }
00514 
00515     /********************************************************************************/
00516 
00517     class stream
00518     {
00519     public:
00520 
00521         typedef typename deque2::value_type value_type;
00522 
00523         typedef typename bid_deque_type::const_iterator bid_iter_type;
00524 
00525     protected:
00526 
00527         const deque2&       m_deque;
00528 
00529         size_type           m_size;
00530 
00531         value_type*         m_current_element;
00532 
00533         block_type*         m_current_block;
00534 
00535         bid_iter_type       m_next_bid;
00536 
00537     public:
00538 
00539         stream(const deque2& deque2)
00540             : m_deque(deque2),
00541               m_size(deque2.size())
00542         {
00543             m_current_block = deque2.m_front_block;
00544             m_current_element = deque2.m_front_element;
00545             m_next_bid = deque2.m_bids.begin();
00546         }
00547 
00548         ~stream()
00549         {
00550             if ( m_current_block != m_deque.m_front_block &&
00551                  m_current_block != m_deque.m_back_block ) // give m_current_block back to pool
00552                 m_deque.m_pool->add(m_current_block);
00553         }
00554 
00555         size_type size() const
00556         {
00557             return m_size;
00558         }
00559 
00560         bool empty() const
00561         {
00562             return (m_size == 0);
00563         }
00564 
00565         const value_type& operator*() const
00566         {
00567             assert(!empty());
00568             return *m_current_element;
00569         }
00570 
00571         stream& operator++()
00572         {
00573             assert(!empty());
00574 
00575             if (UNLIKELY(m_current_element == m_current_block->begin() + (block_type::size - 1)))
00576             {
00577                 // next item position is beyond end of current block, find next block
00578                 --m_size;
00579 
00580                 if (m_size == 0)
00581                 {
00582                     STXXL_VERBOSE1("deque2::stream::operator++ last block finished clean at block end");
00583                     assert( m_next_bid == m_deque.m_bids.end() );
00584                     assert( m_current_block == m_deque.m_back_block );
00585                     // nothing to give back to deque pool
00586                     m_current_element = NULL;
00587                     return *this;
00588                 }
00589                 else if (m_size <= block_type::size)    // still items left in last partial block
00590                 {
00591                     STXXL_VERBOSE1("deque2::stream::operator++ reached last block");
00592                     assert( m_next_bid == m_deque.m_bids.end() );
00593                     // the m_back_block is the next block
00594                     if (m_current_block != m_deque.m_front_block) // give current_block back to pool
00595                         m_deque.m_pool->add(m_current_block);
00596                     m_current_block = m_deque.m_back_block;
00597                     m_current_element = m_current_block->begin();
00598                     return *this;
00599                 }
00600                 else if (m_current_block == m_deque.m_front_block)
00601                 {
00602                     STXXL_VERBOSE1("deque2::stream::operator++ first own-block case: steal block from deque's pool");
00603                     m_current_block = m_deque.m_pool->steal();
00604                 }
00605 
00606                 STXXL_VERBOSE1("deque2::stream::operator++ default case: fetch next block");
00607 
00608                 assert( m_next_bid != m_deque.m_bids.end() );
00609                 request_ptr req = m_deque.m_pool->read(m_current_block, *m_next_bid);
00610                 STXXL_VERBOSE_DEQUE2("deque2[" << this << "]::stream::operator++ read block " << m_current_block << " @ " << FMT_BID(*m_next_bid));
00611 
00612                 // give prefetching hints
00613                 bid_iter_type bid = m_next_bid+1;
00614                 for (unsigned_type i = 0; i < m_deque.m_blocks2prefetch && bid != m_deque.m_bids.end(); ++i, ++bid)
00615                 {
00616                     STXXL_VERBOSE1("deque2::stream::operator++ giving prefetch hints");
00617                     m_deque.m_pool->hint(*bid);
00618                 }
00619 
00620                 m_current_element = m_current_block->begin();
00621                 req->wait();
00622 
00623                 ++m_next_bid;
00624             }
00625             else
00626             {
00627                 --m_size;
00628                 ++m_current_element;
00629             }
00630             return *this;
00631         }
00632     };
00633 
00634     stream get_stream()
00635     {
00636         return stream(*this);
00637     }
00638 
00639     /********************************************************************************/
00640 
00641     class reverse_stream
00642     {
00643     public:
00644 
00645         typedef typename deque2::value_type value_type;
00646 
00647         typedef typename bid_deque_type::const_reverse_iterator bid_iter_type;
00648 
00649     protected:
00650 
00651         const deque2&       m_deque;
00652 
00653         size_type           m_size;
00654 
00655         value_type*         m_current_element;
00656 
00657         block_type*         m_current_block;
00658 
00659         bid_iter_type       m_next_bid;
00660 
00661     public:
00662 
00663         reverse_stream(const deque2& deque2)
00664             : m_deque(deque2),
00665               m_size(deque2.size())
00666         {
00667             m_current_block = deque2.m_back_block;
00668             m_current_element = deque2.m_back_element;
00669             m_next_bid = deque2.m_bids.rbegin();
00670         }
00671 
00672         ~reverse_stream()
00673         {
00674             if ( m_current_block != m_deque.m_front_block &&
00675                  m_current_block != m_deque.m_back_block ) // give m_current_block back to pool
00676                 m_deque.m_pool->add(m_current_block);
00677         }
00678 
00679         size_type size() const
00680         {
00681             return m_size;
00682         }
00683 
00684         bool empty() const
00685         {
00686             return (m_size == 0);
00687         }
00688 
00689         const value_type& operator*() const
00690         {
00691             assert(!empty());
00692             return *m_current_element;
00693         }
00694 
00695         reverse_stream& operator++()
00696         {
00697             assert(!empty());
00698 
00699             if (UNLIKELY(m_current_element == m_current_block->begin()))
00700             {
00701                 // next item position is beyond begin of current block, find next block
00702                 --m_size;
00703 
00704                 if (m_size == 0)
00705                 {
00706                     STXXL_VERBOSE1("deque2::reverse_stream::operator++ last block finished clean at block begin");
00707                     assert( m_next_bid == m_deque.m_bids.rend() );
00708                     assert( m_current_block == m_deque.m_front_block );
00709                     // nothing to give back to deque pool
00710                     m_current_element = NULL;
00711                     return *this;
00712                 }
00713                 else if (m_size <= block_type::size)
00714                 {
00715                     STXXL_VERBOSE1("deque2::reverse_stream::operator++ reached first block");
00716                     assert( m_next_bid == m_deque.m_bids.rend() );
00717                     // the m_back_block is the next block
00718                     if (m_current_block != m_deque.m_back_block) // give current_block back to pool
00719                         m_deque.m_pool->add(m_current_block);
00720                     m_current_block = m_deque.m_front_block;
00721                     m_current_element = m_current_block->begin() + (block_type::size - 1);
00722                     return *this;
00723                 }
00724                 else if (m_current_block == m_deque.m_back_block)
00725                 {
00726                     STXXL_VERBOSE1("deque2::reverse_stream::operator++ first own-block case: steal block from deque's pool");
00727                     m_current_block = m_deque.m_pool->steal();
00728                 }
00729 
00730                 STXXL_VERBOSE1("deque2::reverse_stream::operator++ default case: fetch previous block");
00731 
00732                 assert( m_next_bid != m_deque.m_bids.rend() );
00733                 request_ptr req = m_deque.m_pool->read(m_current_block, *m_next_bid);
00734                 STXXL_VERBOSE_DEQUE2("deque2[" << this << "]::reverse_stream::operator++ read block " << m_current_block << " @ " << FMT_BID(*m_next_bid));
00735 
00736                 // give prefetching hints
00737                 bid_iter_type bid = m_next_bid+1;
00738                 for (unsigned_type i = 0; i < m_deque.m_blocks2prefetch && bid != m_deque.m_bids.rend(); ++i, ++bid)
00739                 {
00740                     STXXL_VERBOSE1("deque2::reverse_stream::operator++ giving prefetch hints");
00741                     m_deque.m_pool->hint(*bid);
00742                 }
00743 
00744                 m_current_element = m_current_block->begin() + (block_type::size - 1);
00745                 req->wait();
00746 
00747                 ++m_next_bid;
00748             }
00749             else
00750             {
00751                 --m_size;
00752                 --m_current_element;
00753             }
00754             return *this;
00755         }
00756     };
00757 
00758     reverse_stream get_reverse_stream()
00759     {
00760         return reverse_stream(*this);
00761     }
00762 };
00763 
00764 //! \}
00765 
00766 __STXXL_END_NAMESPACE
00767 
00768 #endif // !STXXL_DEQUE2_HEADER
00769 // vim: et:ts=4:sw=4
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines