Orocos Real-Time Toolkit  2.5.0
oro_allocator.hpp
00001 /***************************************************************************
00002   tag: Peter Soetens  Thu Oct 22 11:59:07 CEST 2009  oro_allocator.hpp
00003 
00004                         oro_allocator.hpp -  description
00005                            -------------------
00006     begin                : Thu October 22 2009
00007     copyright            : (C) 2009 Peter Soetens
00008     email                : peter@thesourcworks.com
00009 
00010  ***************************************************************************
00011  *   This library is free software; you can redistribute it and/or         *
00012  *   modify it under the terms of the GNU General Public                   *
00013  *   License as published by the Free Software Foundation;                 *
00014  *   version 2 of the License.                                             *
00015  *                                                                         *
00016  *   As a special exception, you may use this file as part of a free       *
00017  *   software library without restriction.  Specifically, if other files   *
00018  *   instantiate templates or use macros or inline functions from this     *
00019  *   file, or you compile this file and link it with other files to        *
00020  *   produce an executable, this file does not by itself cause the         *
00021  *   resulting executable to be covered by the GNU General Public          *
00022  *   License.  This exception does not however invalidate any other        *
00023  *   reasons why the executable file might be covered by the GNU General   *
00024  *   Public License.                                                       *
00025  *                                                                         *
00026  *   This library is distributed in the hope that it will be useful,       *
00027  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00028  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
00029  *   Lesser General Public License for more details.                       *
00030  *                                                                         *
00031  *   You should have received a copy of the GNU General Public             *
00032  *   License along with this library; if not, write to the Free Software   *
00033  *   Foundation, Inc., 59 Temple Place,                                    *
00034  *   Suite 330, Boston, MA  02111-1307  USA                                *
00035  *                                                                         *
00036  ***************************************************************************/
00037 
00038 
00039 #ifndef ORO_ALOCATOR_HPP
00040 #define ORO_ALOCATOR_HPP
00041 
00042 #include <memory>
00043 #include <utility>
00044 #include <map>
00045 
00046 #include "MutexLock.hpp"
00047 #include "oro_malloc.h"
00048 
00049 namespace RTT { namespace os {
00063     template <class T, class Alloc = std::allocator<T> >
00064     class local_allocator
00065     {
00066     public:
00067         typedef typename Alloc::value_type      value_type;
00068         typedef typename Alloc::pointer         pointer;
00069         typedef typename Alloc::const_pointer   const_pointer;
00070         typedef typename Alloc::reference       reference;
00071         typedef typename Alloc::const_reference const_reference;
00072         typedef typename Alloc::size_type       size_type;
00073         typedef typename Alloc::difference_type difference_type;
00074         //...
00075     public:
00076         pointer address(reference x) const {
00077             return Alloc().address(x);
00078         }
00079 
00080         const_pointer address(const_reference x) const {
00081             return Alloc().address(x);
00082         }
00083     public:
00084         pointer allocate(size_type n, const_pointer hint = 0) {
00085             pointer ret = 0;
00086             if (n == 0)
00087                 return ret;
00088             MutexLock lock( pool_lock );
00089             // if present in pool, return pool item
00090             std::pair<pool_it,pool_it> r = pool.equal_range( n );
00091             while ( r.first != r.second && r.first->second == 0  )
00092                 ++r.first;
00093             // if found, return item :
00094             if ( r.first != r.second ) {
00095                 ret = r.first->second;
00096                 r.first->second = 0; // clear out
00097                 //std::cerr << "Using grown: "<< ret<<" of size "<<n<<" in "<<typeid(ret).name()<<std::endl;
00098                 return ret;
00099             }
00100 
00101             // fallback on allocator...
00102             // ret is still zero here
00103             pool.insert( typename pool_type::value_type(n,ret) );     // store free location.
00104             ret = this->_grow(n, hint);
00105             //std::cerr << "Allocated ungrown: "<< ret<<" of size "<<n<<" in "<<typeid(ret).name()<<std::endl;
00106 
00107             return ret;
00108         }
00109 
00110         void deallocate(pointer p, size_type n) {
00111             MutexLock lock( pool_lock );
00112             std::pair<pool_it,pool_it> r = pool.equal_range( n );
00113 //             if ( find( r.first, r.second, typename pool_type::value_type(n,p) ) != r.second )
00114 //                 assert(false && "Do not deallocate twice !");
00115             while ( r.first != r.second && r.first->second != 0  )
00116                 ++r.first;
00117             // if found, store item :
00118             if ( r.first != r.second ) {
00119                 r.first->second = p;
00120                 //std::cerr << "Storing grown: "<< p <<" of size "<<n<<" in "<<typeid(p).name()<<std::endl;
00121                 return;
00122             }
00123             // if not found, we did not allocate it !
00124             //std::cerr << "Deallocating ungrown: "<<p << " of size "<<n<<" in "<<typeid(p).name()<<std::endl;
00125             this->_shrink(p,n);
00126         }
00127 
00128         size_type max_size() const {
00129             return Alloc().max_size();
00130         }
00131 
00132         void construct(pointer p, const value_type& x) {
00133             Alloc().construct(p, x);
00134         }
00135 
00136         void destroy(pointer p) { Alloc().destroy(p); }
00137 
00141         void grow(size_type n, const_pointer hint = 0) {
00142             MutexLock lock( pool_lock );
00143             pointer ret = this->_grow(n, hint);
00144             pool.insert( typename pool_type::value_type( n,ret ) );     // store mem location.
00145             //std::cerr << "Added   : "<< ret<<" of size "<<n<<" in "<<typeid(ret).name()<<std::endl;
00146         }
00147 
00151         void shrink(size_type n) {
00152             if (n == 0)
00153                 return;
00154             MutexLock lock( pool_lock );
00155             std::pair<pool_it,pool_it> r = pool.equal_range( n );
00156             while ( r.first != r.second && r.first->second == 0  )
00157                 ++r.first;
00158             if ( r.first != r.second ) {
00159                 pointer t = r.first->second;
00160                 pool.erase( r.first ); // erase unused slot.
00161                 //std::cerr << "Removed: "<<t << " of size "<<n<<" in "<<typeid(t).name()<<std::endl;
00162                 _shrink(t,n);
00163                 return;
00164             }
00165             //std::cerr << "Unable to remove "<<n<<std::endl;
00166         }
00167     public:
00168         local_allocator() {}
00169         local_allocator(const local_allocator&) {}
00170         ~local_allocator() {}
00171         template <class U, class A>
00172         local_allocator(const local_allocator<U,A>&) {}
00173 
00174         template <class U>
00175         struct rebind { typedef local_allocator<U, typename Alloc::template rebind<U>::other > other; };
00176     private:
00177         Mutex pool_lock;
00181         pointer _grow(size_type n, const_pointer hint = 0) {
00182             return Alloc().allocate( n, hint );
00183         }
00184 
00185         void _shrink( pointer t, size_type n) {
00186             Alloc().deallocate( t, n);
00187         }
00188 
00189         void operator=(const local_allocator&);
00190 
00191         // the pool stores block-size/pointer pairs. Also uses Alloc for allocation.
00192         typedef std::multimap< size_t, pointer> pool_type;
00193         typedef typename pool_type::iterator       pool_it;
00194         typedef typename pool_type::const_iterator pool_cit;
00195         // stores blocks -> memory map for allocated memory.
00196         struct pool_wrapper_type : public pool_type {
00197             ~pool_wrapper_type() {
00198                 // free all memory.
00199                 typename pool_type::iterator it = this->begin();
00200                 for (; it != this->end(); ++it ) {
00201                     Alloc().deallocate(it->second, it->first );
00202                 }
00203             }
00204         };
00205         static pool_wrapper_type pool;
00206 
00207     };
00208 
00209     template< class T, class A>
00210     typename local_allocator<T,A>::pool_wrapper_type local_allocator<T,A>::pool;
00211 
00212 //     template< class T, class A>
00213 //     Mutex local_allocator<T,A>::pool_lock;
00214 
00215     template <class T, class A, class A2>
00216     inline bool operator==(const local_allocator<T,A>& ,
00217                            const local_allocator<T,A2>& ) {
00218         return false;
00219     }
00220 
00221     template <class T, class A, class A2>
00222     inline bool operator!=(const local_allocator<T,A>& ,
00223                            const local_allocator<T,A2>& ) {
00224         return true;
00225     }
00226 
00227     template <class T, class A>
00228     inline bool operator==(const local_allocator<T,A>& ,
00229                            const local_allocator<T,A>& ) {
00230         return true;;
00231     }
00232 
00233     template <class T, class A>
00234     inline bool operator!=(const local_allocator<T,A>&,
00235                            const local_allocator<T,A>&) {
00236         return false;
00237     }
00238 
00239     template<>
00240     class local_allocator<void>
00241     {
00242         typedef void    value_type;
00243         typedef void*       pointer;
00244         typedef const void* const_pointer;
00245 
00246         template <class U>
00247         struct rebind { typedef local_allocator<U> other; };
00248     };
00249 
00255     template <class T> class rt_allocator
00256     {
00257     public:
00258         typedef T                 value_type;
00259         typedef value_type*       pointer;
00260         typedef const value_type* const_pointer;
00261         typedef value_type&       reference;
00262         typedef const value_type& const_reference;
00263         typedef std::size_t       size_type;
00264         typedef std::ptrdiff_t    difference_type;
00265         //...
00266     public:
00267         pointer address(reference x) const {
00268             return &x;
00269         }
00270 
00271         const_pointer address(const_reference x) const {
00272             return &x;
00273         }
00274     public:
00275         pointer allocate(size_type n, const_pointer = 0) {
00276             void* p = oro_rt_malloc(n * sizeof(T));
00277             if (!p)
00278                 throw std::bad_alloc();
00279             return static_cast<pointer>(p);
00280         }
00281 
00282         void deallocate(pointer p, size_type) {
00283             oro_rt_free(p);
00284         }
00285 
00286         size_type max_size() const {
00287             return static_cast<size_type>(-1) / sizeof(value_type);
00288         }
00289 
00290         void construct(pointer p, const value_type& x) {
00291             new(p) value_type(x);
00292         }
00293 
00294         void destroy(pointer p) { p->~value_type(); }
00295 
00296     public:
00297         rt_allocator() {}
00298         rt_allocator(const rt_allocator&) {}
00299         ~rt_allocator() {}
00300         template <class U>
00301         rt_allocator(const rt_allocator<U>&) {}
00302 
00303         template <class U>
00304         struct rebind { typedef rt_allocator<U> other; };
00305     private:
00306         void operator=(const rt_allocator&);
00307     };
00308 
00309     template <class T>
00310     inline bool operator==(const rt_allocator<T>&,
00311                            const rt_allocator<T>&) {
00312         return true;
00313     }
00314 
00315     template <class T>
00316     inline bool operator!=(const rt_allocator<T>&,
00317                            const rt_allocator<T>&) {
00318         return false;
00319     }
00320 
00321     template<> class rt_allocator<void>
00322     {
00323         typedef void        value_type;
00324         typedef void*       pointer;
00325         typedef const void* const_pointer;
00326 
00327         template <class U>
00328         struct rebind { typedef rt_allocator<U> other; };
00329     };
00330 }}
00331 
00332 #endif