# bitmap_allocator.h

Go to the documentation of this file.

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