Stxxl
1.4.0
|
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