libstdc++
|
00001 // Bitmap Allocator. -*- C++ -*- 00002 00003 // Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 00004 // Free Software Foundation, Inc. 00005 // 00006 // This file is part of the GNU ISO C++ Library. This library is free 00007 // software; you can redistribute it and/or modify it under the 00008 // terms of the GNU General Public License as published by the 00009 // Free Software Foundation; either version 3, or (at your option) 00010 // any later version. 00011 00012 // This library is distributed in the hope that it will be useful, 00013 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 // GNU General Public License for more details. 00016 00017 // Under Section 7 of GPL version 3, you are granted additional 00018 // permissions described in the GCC Runtime Library Exception, version 00019 // 3.1, as published by the Free Software Foundation. 00020 00021 // You should have received a copy of the GNU General Public License and 00022 // a copy of the GCC Runtime Library Exception along with this program; 00023 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 00024 // <http://www.gnu.org/licenses/>. 00025 00026 /** @file ext/bitmap_allocator.h 00027 * This file is a GNU extension to the Standard C++ Library. 00028 */ 00029 00030 #ifndef _BITMAP_ALLOCATOR_H 00031 #define _BITMAP_ALLOCATOR_H 1 00032 00033 #include <utility> // For std::pair. 00034 #include <bits/functexcept.h> // For __throw_bad_alloc(). 00035 #include <functional> // For greater_equal, and less_equal. 00036 #include <new> // For operator new. 00037 #include <debug/debug.h> // _GLIBCXX_DEBUG_ASSERT 00038 #include <ext/concurrence.h> 00039 #include <bits/move.h> 00040 00041 /** @brief The constant in the expression below is the alignment 00042 * required in bytes. 00043 */ 00044 #define _BALLOC_ALIGN_BYTES 8 00045 00046 namespace __gnu_cxx _GLIBCXX_VISIBILITY(default) 00047 { 00048 using std::size_t; 00049 using std::ptrdiff_t; 00050 00051 namespace __detail 00052 { 00053 _GLIBCXX_BEGIN_NAMESPACE_VERSION 00054 /** @class __mini_vector bitmap_allocator.h bitmap_allocator.h 00055 * 00056 * @brief __mini_vector<> is a stripped down version of the 00057 * full-fledged std::vector<>. 00058 * 00059 * It is to be used only for built-in types or PODs. Notable 00060 * differences are: 00061 * 00062 * 1. Not all accessor functions are present. 00063 * 2. Used ONLY for PODs. 00064 * 3. No Allocator template argument. Uses ::operator new() to get 00065 * memory, and ::operator delete() to free it. 00066 * Caveat: The dtor does NOT free the memory allocated, so this a 00067 * memory-leaking vector! 00068 */ 00069 template<typename _Tp> 00070 class __mini_vector 00071 { 00072 __mini_vector(const __mini_vector&); 00073 __mini_vector& operator=(const __mini_vector&); 00074 00075 public: 00076 typedef _Tp value_type; 00077 typedef _Tp* pointer; 00078 typedef _Tp& reference; 00079 typedef const _Tp& const_reference; 00080 typedef size_t size_type; 00081 typedef ptrdiff_t difference_type; 00082 typedef pointer iterator; 00083 00084 private: 00085 pointer _M_start; 00086 pointer _M_finish; 00087 pointer _M_end_of_storage; 00088 00089 size_type 00090 _M_space_left() const throw() 00091 { return _M_end_of_storage - _M_finish; } 00092 00093 pointer 00094 allocate(size_type __n) 00095 { return static_cast<pointer>(::operator new(__n * sizeof(_Tp))); } 00096 00097 void 00098 deallocate(pointer __p, size_type) 00099 { ::operator delete(__p); } 00100 00101 public: 00102 // Members used: size(), push_back(), pop_back(), 00103 // insert(iterator, const_reference), erase(iterator), 00104 // begin(), end(), back(), operator[]. 00105 00106 __mini_vector() 00107 : _M_start(0), _M_finish(0), _M_end_of_storage(0) { } 00108 00109 size_type 00110 size() const throw() 00111 { return _M_finish - _M_start; } 00112 00113 iterator 00114 begin() const throw() 00115 { return this->_M_start; } 00116 00117 iterator 00118 end() const throw() 00119 { return this->_M_finish; } 00120 00121 reference 00122 back() const throw() 00123 { return *(this->end() - 1); } 00124 00125 reference 00126 operator[](const size_type __pos) const throw() 00127 { return this->_M_start[__pos]; } 00128 00129 void 00130 insert(iterator __pos, const_reference __x); 00131 00132 void 00133 push_back(const_reference __x) 00134 { 00135 if (this->_M_space_left()) 00136 { 00137 *this->end() = __x; 00138 ++this->_M_finish; 00139 } 00140 else 00141 this->insert(this->end(), __x); 00142 } 00143 00144 void 00145 pop_back() throw() 00146 { --this->_M_finish; } 00147 00148 void 00149 erase(iterator __pos) throw(); 00150 00151 void 00152 clear() throw() 00153 { this->_M_finish = this->_M_start; } 00154 }; 00155 00156 // Out of line function definitions. 00157 template<typename _Tp> 00158 void __mini_vector<_Tp>:: 00159 insert(iterator __pos, const_reference __x) 00160 { 00161 if (this->_M_space_left()) 00162 { 00163 size_type __to_move = this->_M_finish - __pos; 00164 iterator __dest = this->end(); 00165 iterator __src = this->end() - 1; 00166 00167 ++this->_M_finish; 00168 while (__to_move) 00169 { 00170 *__dest = *__src; 00171 --__dest; --__src; --__to_move; 00172 } 00173 *__pos = __x; 00174 } 00175 else 00176 { 00177 size_type __new_size = this->size() ? this->size() * 2 : 1; 00178 iterator __new_start = this->allocate(__new_size); 00179 iterator __first = this->begin(); 00180 iterator __start = __new_start; 00181 while (__first != __pos) 00182 { 00183 *__start = *__first; 00184 ++__start; ++__first; 00185 } 00186 *__start = __x; 00187 ++__start; 00188 while (__first != this->end()) 00189 { 00190 *__start = *__first; 00191 ++__start; ++__first; 00192 } 00193 if (this->_M_start) 00194 this->deallocate(this->_M_start, this->size()); 00195 00196 this->_M_start = __new_start; 00197 this->_M_finish = __start; 00198 this->_M_end_of_storage = this->_M_start + __new_size; 00199 } 00200 } 00201 00202 template<typename _Tp> 00203 void __mini_vector<_Tp>:: 00204 erase(iterator __pos) throw() 00205 { 00206 while (__pos + 1 != this->end()) 00207 { 00208 *__pos = __pos[1]; 00209 ++__pos; 00210 } 00211 --this->_M_finish; 00212 } 00213 00214 00215 template<typename _Tp> 00216 struct __mv_iter_traits 00217 { 00218 typedef typename _Tp::value_type value_type; 00219 typedef typename _Tp::difference_type difference_type; 00220 }; 00221 00222 template<typename _Tp> 00223 struct __mv_iter_traits<_Tp*> 00224 { 00225 typedef _Tp value_type; 00226 typedef ptrdiff_t difference_type; 00227 }; 00228 00229 enum 00230 { 00231 bits_per_byte = 8, 00232 bits_per_block = sizeof(size_t) * size_t(bits_per_byte) 00233 }; 00234 00235 template<typename _ForwardIterator, typename _Tp, typename _Compare> 00236 _ForwardIterator 00237 __lower_bound(_ForwardIterator __first, _ForwardIterator __last, 00238 const _Tp& __val, _Compare __comp) 00239 { 00240 typedef typename __mv_iter_traits<_ForwardIterator>::difference_type 00241 _DistanceType; 00242 00243 _DistanceType __len = __last - __first; 00244 _DistanceType __half; 00245 _ForwardIterator __middle; 00246 00247 while (__len > 0) 00248 { 00249 __half = __len >> 1; 00250 __middle = __first; 00251 __middle += __half; 00252 if (__comp(*__middle, __val)) 00253 { 00254 __first = __middle; 00255 ++__first; 00256 __len = __len - __half - 1; 00257 } 00258 else 00259 __len = __half; 00260 } 00261 return __first; 00262 } 00263 00264 /** @brief The number of Blocks pointed to by the address pair 00265 * passed to the function. 00266 */ 00267 template<typename _AddrPair> 00268 inline size_t 00269 __num_blocks(_AddrPair __ap) 00270 { return (__ap.second - __ap.first) + 1; } 00271 00272 /** @brief The number of Bit-maps pointed to by the address pair 00273 * passed to the function. 00274 */ 00275 template<typename _AddrPair> 00276 inline size_t 00277 __num_bitmaps(_AddrPair __ap) 00278 { return __num_blocks(__ap) / size_t(bits_per_block); } 00279 00280 // _Tp should be a pointer type. 00281 template<typename _Tp> 00282 class _Inclusive_between 00283 : public std::unary_function<typename std::pair<_Tp, _Tp>, bool> 00284 { 00285 typedef _Tp pointer; 00286 pointer _M_ptr_value; 00287 typedef typename std::pair<_Tp, _Tp> _Block_pair; 00288 00289 public: 00290 _Inclusive_between(pointer __ptr) : _M_ptr_value(__ptr) 00291 { } 00292 00293 bool 00294 operator()(_Block_pair __bp) const throw() 00295 { 00296 if (std::less_equal<pointer>()(_M_ptr_value, __bp.second) 00297 && std::greater_equal<pointer>()(_M_ptr_value, __bp.first)) 00298 return true; 00299 else 00300 return false; 00301 } 00302 }; 00303 00304 // Used to pass a Functor to functions by reference. 00305 template<typename _Functor> 00306 class _Functor_Ref 00307 : public std::unary_function<typename _Functor::argument_type, 00308 typename _Functor::result_type> 00309 { 00310 _Functor& _M_fref; 00311 00312 public: 00313 typedef typename _Functor::argument_type argument_type; 00314 typedef typename _Functor::result_type result_type; 00315 00316 _Functor_Ref(_Functor& __fref) : _M_fref(__fref) 00317 { } 00318 00319 result_type 00320 operator()(argument_type __arg) 00321 { return _M_fref(__arg); } 00322 }; 00323 00324 /** @class _Ffit_finder bitmap_allocator.h bitmap_allocator.h 00325 * 00326 * @brief The class which acts as a predicate for applying the 00327 * first-fit memory allocation policy for the bitmap allocator. 00328 */ 00329 // _Tp should be a pointer type, and _Alloc is the Allocator for 00330 // the vector. 00331 template<typename _Tp> 00332 class _Ffit_finder 00333 : public std::unary_function<typename std::pair<_Tp, _Tp>, bool> 00334 { 00335 typedef typename std::pair<_Tp, _Tp> _Block_pair; 00336 typedef typename __detail::__mini_vector<_Block_pair> _BPVector; 00337 typedef typename _BPVector::difference_type _Counter_type; 00338 00339 size_t* _M_pbitmap; 00340 _Counter_type _M_data_offset; 00341 00342 public: 00343 _Ffit_finder() : _M_pbitmap(0), _M_data_offset(0) 00344 { } 00345 00346 bool 00347 operator()(_Block_pair __bp) throw() 00348 { 00349 // Set the _rover to the last physical location bitmap, 00350 // which is the bitmap which belongs to the first free 00351 // block. Thus, the bitmaps are in exact reverse order of 00352 // the actual memory layout. So, we count down the bitmaps, 00353 // which is the same as moving up the memory. 00354 00355 // If the used count stored at the start of the Bit Map headers 00356 // is equal to the number of Objects that the current Block can 00357 // store, then there is definitely no space for another single 00358 // object, so just return false. 00359 _Counter_type __diff = __detail::__num_bitmaps(__bp); 00360 00361 if (*(reinterpret_cast<size_t*> 00362 (__bp.first) - (__diff + 1)) == __detail::__num_blocks(__bp)) 00363 return false; 00364 00365 size_t* __rover = reinterpret_cast<size_t*>(__bp.first) - 1; 00366 00367 for (_Counter_type __i = 0; __i < __diff; ++__i) 00368 { 00369 _M_data_offset = __i; 00370 if (*__rover) 00371 { 00372 _M_pbitmap = __rover; 00373 return true; 00374 } 00375 --__rover; 00376 } 00377 return false; 00378 } 00379 00380 size_t* 00381 _M_get() const throw() 00382 { return _M_pbitmap; } 00383 00384 _Counter_type 00385 _M_offset() const throw() 00386 { return _M_data_offset * size_t(bits_per_block); } 00387 }; 00388 00389 /** @class _Bitmap_counter bitmap_allocator.h bitmap_allocator.h 00390 * 00391 * @brief The bitmap counter which acts as the bitmap 00392 * manipulator, and manages the bit-manipulation functions and 00393 * the searching and identification functions on the bit-map. 00394 */ 00395 // _Tp should be a pointer type. 00396 template<typename _Tp> 00397 class _Bitmap_counter 00398 { 00399 typedef typename 00400 __detail::__mini_vector<typename std::pair<_Tp, _Tp> > _BPVector; 00401 typedef typename _BPVector::size_type _Index_type; 00402 typedef _Tp pointer; 00403 00404 _BPVector& _M_vbp; 00405 size_t* _M_curr_bmap; 00406 size_t* _M_last_bmap_in_block; 00407 _Index_type _M_curr_index; 00408 00409 public: 00410 // Use the 2nd parameter with care. Make sure that such an 00411 // entry exists in the vector before passing that particular 00412 // index to this ctor. 00413 _Bitmap_counter(_BPVector& Rvbp, long __index = -1) : _M_vbp(Rvbp) 00414 { this->_M_reset(__index); } 00415 00416 void 00417 _M_reset(long __index = -1) throw() 00418 { 00419 if (__index == -1) 00420 { 00421 _M_curr_bmap = 0; 00422 _M_curr_index = static_cast<_Index_type>(-1); 00423 return; 00424 } 00425 00426 _M_curr_index = __index; 00427 _M_curr_bmap = reinterpret_cast<size_t*> 00428 (_M_vbp[_M_curr_index].first) - 1; 00429 00430 _GLIBCXX_DEBUG_ASSERT(__index <= (long)_M_vbp.size() - 1); 00431 00432 _M_last_bmap_in_block = _M_curr_bmap 00433 - ((_M_vbp[_M_curr_index].second 00434 - _M_vbp[_M_curr_index].first + 1) 00435 / size_t(bits_per_block) - 1); 00436 } 00437 00438 // Dangerous Function! Use with extreme care. Pass to this 00439 // function ONLY those values that are known to be correct, 00440 // otherwise this will mess up big time. 00441 void 00442 _M_set_internal_bitmap(size_t* __new_internal_marker) throw() 00443 { _M_curr_bmap = __new_internal_marker; } 00444 00445 bool 00446 _M_finished() const throw() 00447 { return(_M_curr_bmap == 0); } 00448 00449 _Bitmap_counter& 00450 operator++() throw() 00451 { 00452 if (_M_curr_bmap == _M_last_bmap_in_block) 00453 { 00454 if (++_M_curr_index == _M_vbp.size()) 00455 _M_curr_bmap = 0; 00456 else 00457 this->_M_reset(_M_curr_index); 00458 } 00459 else 00460 --_M_curr_bmap; 00461 return *this; 00462 } 00463 00464 size_t* 00465 _M_get() const throw() 00466 { return _M_curr_bmap; } 00467 00468 pointer 00469 _M_base() const throw() 00470 { return _M_vbp[_M_curr_index].first; } 00471 00472 _Index_type 00473 _M_offset() const throw() 00474 { 00475 return size_t(bits_per_block) 00476 * ((reinterpret_cast<size_t*>(this->_M_base()) 00477 - _M_curr_bmap) - 1); 00478 } 00479 00480 _Index_type 00481 _M_where() const throw() 00482 { return _M_curr_index; } 00483 }; 00484 00485 /** @brief Mark a memory address as allocated by re-setting the 00486 * corresponding bit in the bit-map. 00487 */ 00488 inline void 00489 __bit_allocate(size_t* __pbmap, size_t __pos) throw() 00490 { 00491 size_t __mask = 1 << __pos; 00492 __mask = ~__mask; 00493 *__pbmap &= __mask; 00494 } 00495 00496 /** @brief Mark a memory address as free by setting the 00497 * corresponding bit in the bit-map. 00498 */ 00499 inline void 00500 __bit_free(size_t* __pbmap, size_t __pos) throw() 00501 { 00502 size_t __mask = 1 << __pos; 00503 *__pbmap |= __mask; 00504 } 00505 00506 _GLIBCXX_END_NAMESPACE_VERSION 00507 } // namespace __detail 00508 00509 _GLIBCXX_BEGIN_NAMESPACE_VERSION 00510 00511 /** @brief Generic Version of the bsf instruction. 00512 */ 00513 inline size_t 00514 _Bit_scan_forward(size_t __num) 00515 { return static_cast<size_t>(__builtin_ctzl(__num)); } 00516 00517 /** @class free_list bitmap_allocator.h bitmap_allocator.h 00518 * 00519 * @brief The free list class for managing chunks of memory to be 00520 * given to and returned by the bitmap_allocator. 00521 */ 00522 class free_list 00523 { 00524 public: 00525 typedef size_t* value_type; 00526 typedef __detail::__mini_vector<value_type> vector_type; 00527 typedef vector_type::iterator iterator; 00528 typedef __mutex __mutex_type; 00529 00530 private: 00531 struct _LT_pointer_compare 00532 { 00533 bool 00534 operator()(const size_t* __pui, 00535 const size_t __cui) const throw() 00536 { return *__pui < __cui; } 00537 }; 00538 00539 #if defined __GTHREADS 00540 __mutex_type& 00541 _M_get_mutex() 00542 { 00543 static __mutex_type _S_mutex; 00544 return _S_mutex; 00545 } 00546 #endif 00547 00548 vector_type& 00549 _M_get_free_list() 00550 { 00551 static vector_type _S_free_list; 00552 return _S_free_list; 00553 } 00554 00555 /** @brief Performs validation of memory based on their size. 00556 * 00557 * @param __addr The pointer to the memory block to be 00558 * validated. 00559 * 00560 * Validates the memory block passed to this function and 00561 * appropriately performs the action of managing the free list of 00562 * blocks by adding this block to the free list or deleting this 00563 * or larger blocks from the free list. 00564 */ 00565 void 00566 _M_validate(size_t* __addr) throw() 00567 { 00568 vector_type& __free_list = _M_get_free_list(); 00569 const vector_type::size_type __max_size = 64; 00570 if (__free_list.size() >= __max_size) 00571 { 00572 // Ok, the threshold value has been reached. We determine 00573 // which block to remove from the list of free blocks. 00574 if (*__addr >= *__free_list.back()) 00575 { 00576 // Ok, the new block is greater than or equal to the 00577 // last block in the list of free blocks. We just free 00578 // the new block. 00579 ::operator delete(static_cast<void*>(__addr)); 00580 return; 00581 } 00582 else 00583 { 00584 // Deallocate the last block in the list of free lists, 00585 // and insert the new one in its correct position. 00586 ::operator delete(static_cast<void*>(__free_list.back())); 00587 __free_list.pop_back(); 00588 } 00589 } 00590 00591 // Just add the block to the list of free lists unconditionally. 00592 iterator __temp = __detail::__lower_bound 00593 (__free_list.begin(), __free_list.end(), 00594 *__addr, _LT_pointer_compare()); 00595 00596 // We may insert the new free list before _temp; 00597 __free_list.insert(__temp, __addr); 00598 } 00599 00600 /** @brief Decides whether the wastage of memory is acceptable for 00601 * the current memory request and returns accordingly. 00602 * 00603 * @param __block_size The size of the block available in the free 00604 * list. 00605 * 00606 * @param __required_size The required size of the memory block. 00607 * 00608 * @return true if the wastage incurred is acceptable, else returns 00609 * false. 00610 */ 00611 bool 00612 _M_should_i_give(size_t __block_size, 00613 size_t __required_size) throw() 00614 { 00615 const size_t __max_wastage_percentage = 36; 00616 if (__block_size >= __required_size && 00617 (((__block_size - __required_size) * 100 / __block_size) 00618 < __max_wastage_percentage)) 00619 return true; 00620 else 00621 return false; 00622 } 00623 00624 public: 00625 /** @brief This function returns the block of memory to the 00626 * internal free list. 00627 * 00628 * @param __addr The pointer to the memory block that was given 00629 * by a call to the _M_get function. 00630 */ 00631 inline void 00632 _M_insert(size_t* __addr) throw() 00633 { 00634 #if defined __GTHREADS 00635 __scoped_lock __bfl_lock(_M_get_mutex()); 00636 #endif 00637 // Call _M_validate to decide what should be done with 00638 // this particular free list. 00639 this->_M_validate(reinterpret_cast<size_t*>(__addr) - 1); 00640 // See discussion as to why this is 1! 00641 } 00642 00643 /** @brief This function gets a block of memory of the specified 00644 * size from the free list. 00645 * 00646 * @param __sz The size in bytes of the memory required. 00647 * 00648 * @return A pointer to the new memory block of size at least 00649 * equal to that requested. 00650 */ 00651 size_t* 00652 _M_get(size_t __sz) throw(std::bad_alloc); 00653 00654 /** @brief This function just clears the internal Free List, and 00655 * gives back all the memory to the OS. 00656 */ 00657 void 00658 _M_clear(); 00659 }; 00660 00661 00662 // Forward declare the class. 00663 template<typename _Tp> 00664 class bitmap_allocator; 00665 00666 // Specialize for void: 00667 template<> 00668 class bitmap_allocator<void> 00669 { 00670 public: 00671 typedef void* pointer; 00672 typedef const void* const_pointer; 00673 00674 // Reference-to-void members are impossible. 00675 typedef void value_type; 00676 template<typename _Tp1> 00677 struct rebind 00678 { 00679 typedef bitmap_allocator<_Tp1> other; 00680 }; 00681 }; 00682 00683 /** 00684 * @brief Bitmap Allocator, primary template. 00685 * @ingroup allocators 00686 */ 00687 template<typename _Tp> 00688 class bitmap_allocator : private free_list 00689 { 00690 public: 00691 typedef size_t size_type; 00692 typedef ptrdiff_t difference_type; 00693 typedef _Tp* pointer; 00694 typedef const _Tp* const_pointer; 00695 typedef _Tp& reference; 00696 typedef const _Tp& const_reference; 00697 typedef _Tp value_type; 00698 typedef free_list::__mutex_type __mutex_type; 00699 00700 template<typename _Tp1> 00701 struct rebind 00702 { 00703 typedef bitmap_allocator<_Tp1> other; 00704 }; 00705 00706 private: 00707 template<size_t _BSize, size_t _AlignSize> 00708 struct aligned_size 00709 { 00710 enum 00711 { 00712 modulus = _BSize % _AlignSize, 00713 value = _BSize + (modulus ? _AlignSize - (modulus) : 0) 00714 }; 00715 }; 00716 00717 struct _Alloc_block 00718 { 00719 char __M_unused[aligned_size<sizeof(value_type), 00720 _BALLOC_ALIGN_BYTES>::value]; 00721 }; 00722 00723 00724 typedef typename std::pair<_Alloc_block*, _Alloc_block*> _Block_pair; 00725 00726 typedef typename __detail::__mini_vector<_Block_pair> _BPVector; 00727 typedef typename _BPVector::iterator _BPiter; 00728 00729 template<typename _Predicate> 00730 static _BPiter 00731 _S_find(_Predicate __p) 00732 { 00733 _BPiter __first = _S_mem_blocks.begin(); 00734 while (__first != _S_mem_blocks.end() && !__p(*__first)) 00735 ++__first; 00736 return __first; 00737 } 00738 00739 #if defined _GLIBCXX_DEBUG 00740 // Complexity: O(lg(N)). Where, N is the number of block of size 00741 // sizeof(value_type). 00742 void 00743 _S_check_for_free_blocks() throw() 00744 { 00745 typedef typename __detail::_Ffit_finder<_Alloc_block*> _FFF; 00746 _BPiter __bpi = _S_find(_FFF()); 00747 00748 _GLIBCXX_DEBUG_ASSERT(__bpi == _S_mem_blocks.end()); 00749 } 00750 #endif 00751 00752 /** @brief Responsible for exponentially growing the internal 00753 * memory pool. 00754 * 00755 * @throw std::bad_alloc. If memory can not be allocated. 00756 * 00757 * Complexity: O(1), but internally depends upon the 00758 * complexity of the function free_list::_M_get. The part where 00759 * the bitmap headers are written has complexity: O(X),where X 00760 * is the number of blocks of size sizeof(value_type) within 00761 * the newly acquired block. Having a tight bound. 00762 */ 00763 void 00764 _S_refill_pool() throw(std::bad_alloc) 00765 { 00766 #if defined _GLIBCXX_DEBUG 00767 _S_check_for_free_blocks(); 00768 #endif 00769 00770 const size_t __num_bitmaps = (_S_block_size 00771 / size_t(__detail::bits_per_block)); 00772 const size_t __size_to_allocate = sizeof(size_t) 00773 + _S_block_size * sizeof(_Alloc_block) 00774 + __num_bitmaps * sizeof(size_t); 00775 00776 size_t* __temp = 00777 reinterpret_cast<size_t*>(this->_M_get(__size_to_allocate)); 00778 *__temp = 0; 00779 ++__temp; 00780 00781 // The Header information goes at the Beginning of the Block. 00782 _Block_pair __bp = 00783 std::make_pair(reinterpret_cast<_Alloc_block*> 00784 (__temp + __num_bitmaps), 00785 reinterpret_cast<_Alloc_block*> 00786 (__temp + __num_bitmaps) 00787 + _S_block_size - 1); 00788 00789 // Fill the Vector with this information. 00790 _S_mem_blocks.push_back(__bp); 00791 00792 for (size_t __i = 0; __i < __num_bitmaps; ++__i) 00793 __temp[__i] = ~static_cast<size_t>(0); // 1 Indicates all Free. 00794 00795 _S_block_size *= 2; 00796 } 00797 00798 static _BPVector _S_mem_blocks; 00799 static size_t _S_block_size; 00800 static __detail::_Bitmap_counter<_Alloc_block*> _S_last_request; 00801 static typename _BPVector::size_type _S_last_dealloc_index; 00802 #if defined __GTHREADS 00803 static __mutex_type _S_mut; 00804 #endif 00805 00806 public: 00807 00808 /** @brief Allocates memory for a single object of size 00809 * sizeof(_Tp). 00810 * 00811 * @throw std::bad_alloc. If memory can not be allocated. 00812 * 00813 * Complexity: Worst case complexity is O(N), but that 00814 * is hardly ever hit. If and when this particular case is 00815 * encountered, the next few cases are guaranteed to have a 00816 * worst case complexity of O(1)! That's why this function 00817 * performs very well on average. You can consider this 00818 * function to have a complexity referred to commonly as: 00819 * Amortized Constant time. 00820 */ 00821 pointer 00822 _M_allocate_single_object() throw(std::bad_alloc) 00823 { 00824 #if defined __GTHREADS 00825 __scoped_lock __bit_lock(_S_mut); 00826 #endif 00827 00828 // The algorithm is something like this: The last_request 00829 // variable points to the last accessed Bit Map. When such a 00830 // condition occurs, we try to find a free block in the 00831 // current bitmap, or succeeding bitmaps until the last bitmap 00832 // is reached. If no free block turns up, we resort to First 00833 // Fit method. 00834 00835 // WARNING: Do not re-order the condition in the while 00836 // statement below, because it relies on C++'s short-circuit 00837 // evaluation. The return from _S_last_request->_M_get() will 00838 // NOT be dereference able if _S_last_request->_M_finished() 00839 // returns true. This would inevitably lead to a NULL pointer 00840 // dereference if tinkered with. 00841 while (_S_last_request._M_finished() == false 00842 && (*(_S_last_request._M_get()) == 0)) 00843 _S_last_request.operator++(); 00844 00845 if (__builtin_expect(_S_last_request._M_finished() == true, false)) 00846 { 00847 // Fall Back to First Fit algorithm. 00848 typedef typename __detail::_Ffit_finder<_Alloc_block*> _FFF; 00849 _FFF __fff; 00850 _BPiter __bpi = _S_find(__detail::_Functor_Ref<_FFF>(__fff)); 00851 00852 if (__bpi != _S_mem_blocks.end()) 00853 { 00854 // Search was successful. Ok, now mark the first bit from 00855 // the right as 0, meaning Allocated. This bit is obtained 00856 // by calling _M_get() on __fff. 00857 size_t __nz_bit = _Bit_scan_forward(*__fff._M_get()); 00858 __detail::__bit_allocate(__fff._M_get(), __nz_bit); 00859 00860 _S_last_request._M_reset(__bpi - _S_mem_blocks.begin()); 00861 00862 // Now, get the address of the bit we marked as allocated. 00863 pointer __ret = reinterpret_cast<pointer> 00864 (__bpi->first + __fff._M_offset() + __nz_bit); 00865 size_t* __puse_count = 00866 reinterpret_cast<size_t*> 00867 (__bpi->first) - (__detail::__num_bitmaps(*__bpi) + 1); 00868 00869 ++(*__puse_count); 00870 return __ret; 00871 } 00872 else 00873 { 00874 // Search was unsuccessful. We Add more memory to the 00875 // pool by calling _S_refill_pool(). 00876 _S_refill_pool(); 00877 00878 // _M_Reset the _S_last_request structure to the first 00879 // free block's bit map. 00880 _S_last_request._M_reset(_S_mem_blocks.size() - 1); 00881 00882 // Now, mark that bit as allocated. 00883 } 00884 } 00885 00886 // _S_last_request holds a pointer to a valid bit map, that 00887 // points to a free block in memory. 00888 size_t __nz_bit = _Bit_scan_forward(*_S_last_request._M_get()); 00889 __detail::__bit_allocate(_S_last_request._M_get(), __nz_bit); 00890 00891 pointer __ret = reinterpret_cast<pointer> 00892 (_S_last_request._M_base() + _S_last_request._M_offset() + __nz_bit); 00893 00894 size_t* __puse_count = reinterpret_cast<size_t*> 00895 (_S_mem_blocks[_S_last_request._M_where()].first) 00896 - (__detail:: 00897 __num_bitmaps(_S_mem_blocks[_S_last_request._M_where()]) + 1); 00898 00899 ++(*__puse_count); 00900 return __ret; 00901 } 00902 00903 /** @brief Deallocates memory that belongs to a single object of 00904 * size sizeof(_Tp). 00905 * 00906 * Complexity: O(lg(N)), but the worst case is not hit 00907 * often! This is because containers usually deallocate memory 00908 * close to each other and this case is handled in O(1) time by 00909 * the deallocate function. 00910 */ 00911 void 00912 _M_deallocate_single_object(pointer __p) throw() 00913 { 00914 #if defined __GTHREADS 00915 __scoped_lock __bit_lock(_S_mut); 00916 #endif 00917 _Alloc_block* __real_p = reinterpret_cast<_Alloc_block*>(__p); 00918 00919 typedef typename _BPVector::iterator _Iterator; 00920 typedef typename _BPVector::difference_type _Difference_type; 00921 00922 _Difference_type __diff; 00923 long __displacement; 00924 00925 _GLIBCXX_DEBUG_ASSERT(_S_last_dealloc_index >= 0); 00926 00927 __detail::_Inclusive_between<_Alloc_block*> __ibt(__real_p); 00928 if (__ibt(_S_mem_blocks[_S_last_dealloc_index])) 00929 { 00930 _GLIBCXX_DEBUG_ASSERT(_S_last_dealloc_index 00931 <= _S_mem_blocks.size() - 1); 00932 00933 // Initial Assumption was correct! 00934 __diff = _S_last_dealloc_index; 00935 __displacement = __real_p - _S_mem_blocks[__diff].first; 00936 } 00937 else 00938 { 00939 _Iterator _iter = _S_find(__ibt); 00940 00941 _GLIBCXX_DEBUG_ASSERT(_iter != _S_mem_blocks.end()); 00942 00943 __diff = _iter - _S_mem_blocks.begin(); 00944 __displacement = __real_p - _S_mem_blocks[__diff].first; 00945 _S_last_dealloc_index = __diff; 00946 } 00947 00948 // Get the position of the iterator that has been found. 00949 const size_t __rotate = (__displacement 00950 % size_t(__detail::bits_per_block)); 00951 size_t* __bitmapC = 00952 reinterpret_cast<size_t*> 00953 (_S_mem_blocks[__diff].first) - 1; 00954 __bitmapC -= (__displacement / size_t(__detail::bits_per_block)); 00955 00956 __detail::__bit_free(__bitmapC, __rotate); 00957 size_t* __puse_count = reinterpret_cast<size_t*> 00958 (_S_mem_blocks[__diff].first) 00959 - (__detail::__num_bitmaps(_S_mem_blocks[__diff]) + 1); 00960 00961 _GLIBCXX_DEBUG_ASSERT(*__puse_count != 0); 00962 00963 --(*__puse_count); 00964 00965 if (__builtin_expect(*__puse_count == 0, false)) 00966 { 00967 _S_block_size /= 2; 00968 00969 // We can safely remove this block. 00970 // _Block_pair __bp = _S_mem_blocks[__diff]; 00971 this->_M_insert(__puse_count); 00972 _S_mem_blocks.erase(_S_mem_blocks.begin() + __diff); 00973 00974 // Reset the _S_last_request variable to reflect the 00975 // erased block. We do this to protect future requests 00976 // after the last block has been removed from a particular 00977 // memory Chunk, which in turn has been returned to the 00978 // free list, and hence had been erased from the vector, 00979 // so the size of the vector gets reduced by 1. 00980 if ((_Difference_type)_S_last_request._M_where() >= __diff--) 00981 _S_last_request._M_reset(__diff); 00982 00983 // If the Index into the vector of the region of memory 00984 // that might hold the next address that will be passed to 00985 // deallocated may have been invalidated due to the above 00986 // erase procedure being called on the vector, hence we 00987 // try to restore this invariant too. 00988 if (_S_last_dealloc_index >= _S_mem_blocks.size()) 00989 { 00990 _S_last_dealloc_index =(__diff != -1 ? __diff : 0); 00991 _GLIBCXX_DEBUG_ASSERT(_S_last_dealloc_index >= 0); 00992 } 00993 } 00994 } 00995 00996 public: 00997 bitmap_allocator() _GLIBCXX_USE_NOEXCEPT 00998 { } 00999 01000 bitmap_allocator(const bitmap_allocator&) _GLIBCXX_USE_NOEXCEPT 01001 { } 01002 01003 template<typename _Tp1> 01004 bitmap_allocator(const bitmap_allocator<_Tp1>&) _GLIBCXX_USE_NOEXCEPT 01005 { } 01006 01007 ~bitmap_allocator() _GLIBCXX_USE_NOEXCEPT 01008 { } 01009 01010 pointer 01011 allocate(size_type __n) 01012 { 01013 if (__n > this->max_size()) 01014 std::__throw_bad_alloc(); 01015 01016 if (__builtin_expect(__n == 1, true)) 01017 return this->_M_allocate_single_object(); 01018 else 01019 { 01020 const size_type __b = __n * sizeof(value_type); 01021 return reinterpret_cast<pointer>(::operator new(__b)); 01022 } 01023 } 01024 01025 pointer 01026 allocate(size_type __n, typename bitmap_allocator<void>::const_pointer) 01027 { return allocate(__n); } 01028 01029 void 01030 deallocate(pointer __p, size_type __n) throw() 01031 { 01032 if (__builtin_expect(__p != 0, true)) 01033 { 01034 if (__builtin_expect(__n == 1, true)) 01035 this->_M_deallocate_single_object(__p); 01036 else 01037 ::operator delete(__p); 01038 } 01039 } 01040 01041 pointer 01042 address(reference __r) const _GLIBCXX_NOEXCEPT 01043 { return std::__addressof(__r); } 01044 01045 const_pointer 01046 address(const_reference __r) const _GLIBCXX_NOEXCEPT 01047 { return std::__addressof(__r); } 01048 01049 size_type 01050 max_size() const _GLIBCXX_USE_NOEXCEPT 01051 { return size_type(-1) / sizeof(value_type); } 01052 01053 #ifdef __GXX_EXPERIMENTAL_CXX0X__ 01054 template<typename _Up, typename... _Args> 01055 void 01056 construct(_Up* __p, _Args&&... __args) 01057 { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); } 01058 01059 template<typename _Up> 01060 void 01061 destroy(_Up* __p) 01062 { __p->~_Up(); } 01063 #else 01064 void 01065 construct(pointer __p, const_reference __data) 01066 { ::new((void *)__p) value_type(__data); } 01067 01068 void 01069 destroy(pointer __p) 01070 { __p->~value_type(); } 01071 #endif 01072 }; 01073 01074 template<typename _Tp1, typename _Tp2> 01075 bool 01076 operator==(const bitmap_allocator<_Tp1>&, 01077 const bitmap_allocator<_Tp2>&) throw() 01078 { return true; } 01079 01080 template<typename _Tp1, typename _Tp2> 01081 bool 01082 operator!=(const bitmap_allocator<_Tp1>&, 01083 const bitmap_allocator<_Tp2>&) throw() 01084 { return false; } 01085 01086 // Static member definitions. 01087 template<typename _Tp> 01088 typename bitmap_allocator<_Tp>::_BPVector 01089 bitmap_allocator<_Tp>::_S_mem_blocks; 01090 01091 template<typename _Tp> 01092 size_t bitmap_allocator<_Tp>::_S_block_size = 01093 2 * size_t(__detail::bits_per_block); 01094 01095 template<typename _Tp> 01096 typename bitmap_allocator<_Tp>::_BPVector::size_type 01097 bitmap_allocator<_Tp>::_S_last_dealloc_index = 0; 01098 01099 template<typename _Tp> 01100 __detail::_Bitmap_counter 01101 <typename bitmap_allocator<_Tp>::_Alloc_block*> 01102 bitmap_allocator<_Tp>::_S_last_request(_S_mem_blocks); 01103 01104 #if defined __GTHREADS 01105 template<typename _Tp> 01106 typename bitmap_allocator<_Tp>::__mutex_type 01107 bitmap_allocator<_Tp>::_S_mut; 01108 #endif 01109 01110 _GLIBCXX_END_NAMESPACE_VERSION 01111 } // namespace __gnu_cxx 01112 01113 #endif 01114