Orocos Real-Time Toolkit  2.6.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     public:
00243         typedef void    value_type;
00244         typedef void*       pointer;
00245         typedef const void* const_pointer;
00246 
00247         template <class U>
00248         struct rebind { typedef local_allocator<U> other; };
00249     };
00250 
00256     template <class T> class rt_allocator
00257     {
00258     public:
00259         typedef T                 value_type;
00260         typedef value_type*       pointer;
00261         typedef const value_type* const_pointer;
00262         typedef value_type&       reference;
00263         typedef const value_type& const_reference;
00264         typedef std::size_t       size_type;
00265         typedef std::ptrdiff_t    difference_type;
00266         //...
00267     public:
00268         pointer address(reference x) const {
00269             return &x;
00270         }
00271 
00272         const_pointer address(const_reference x) const {
00273             return &x;
00274         }
00275     public:
00276         pointer allocate(size_type n, const_pointer = 0) {
00277             void* p = oro_rt_malloc(n * sizeof(T));
00278             if (!p)
00279                 throw std::bad_alloc();
00280             return static_cast<pointer>(p);
00281         }
00282 
00283         void deallocate(pointer p, size_type) {
00284             oro_rt_free(p);
00285         }
00286 
00287         size_type max_size() const {
00288             return static_cast<size_type>(-1) / sizeof(value_type);
00289         }
00290 
00291         void construct(pointer p, const value_type& x) {
00292             new(p) value_type(x);
00293         }
00294 
00295         void destroy(pointer p) { p->~value_type(); }
00296 
00297     public:
00298         rt_allocator() {}
00299         rt_allocator(const rt_allocator&) {}
00300         ~rt_allocator() {}
00301         template <class U>
00302         rt_allocator(const rt_allocator<U>&) {}
00303 
00304         template <class U>
00305         struct rebind { typedef rt_allocator<U> other; };
00306     private:
00307         void operator=(const rt_allocator&);
00308     };
00309 
00310     template <class T>
00311     inline bool operator==(const rt_allocator<T>&,
00312                            const rt_allocator<T>&) {
00313         return true;
00314     }
00315 
00316     template <class T>
00317     inline bool operator!=(const rt_allocator<T>&,
00318                            const rt_allocator<T>&) {
00319         return false;
00320     }
00321 
00322     template<> class rt_allocator<void>
00323     {
00324     public:
00325         typedef void        value_type;
00326         typedef void*       pointer;
00327         typedef const void* const_pointer;
00328 
00329         template <class U>
00330         struct rebind { typedef rt_allocator<U> other; };
00331     };
00332 }}
00333 
00334 #endif