Orocos Real-Time Toolkit  2.5.0
ListLocked.hpp
00001 /***************************************************************************
00002   tag: Peter Soetens  Thu Oct 22 11:59:08 CEST 2009  ListLocked.hpp
00003 
00004                         ListLocked.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 
00040 #ifndef ORO_LIST_LOCKED_HPP
00041 #define ORO_LIST_LOCKED_HPP
00042 
00043 #include <boost/intrusive/list.hpp>
00044 #include <boost/bind.hpp>
00045 #include <boost/bind/protect.hpp>
00046 #include <stack>
00047 #include <vector>
00048 #include <algorithm>
00049 #include "../os/Mutex.hpp"
00050 #include "../os/MutexLock.hpp"
00051 
00052 #ifdef ORO_PRAGMA_INTERFACE
00053 #pragma interface
00054 #endif
00055 
00056 namespace RTT
00057 { namespace internal {
00058 
00071     template< class T>
00072     class ListLocked
00073     {
00074     public:
00075 
00076         typedef T value_t;
00077     private:
00078         struct Cont :  public boost::intrusive::list_base_hook<> {
00079             T data;
00080         };
00081         typedef boost::intrusive::list<Cont> BufferType;
00082         typedef std::stack<Cont*> StackType;
00083         typedef typename BufferType::iterator Iterator;
00084         typedef typename BufferType::const_iterator CIterator;
00085 
00086         BufferType mlist;
00087         StackType  mreserved;
00088         unsigned int required;
00089 
00090         mutable os::MutexRecursive m;
00091     public:
00096         ListLocked(unsigned int lsize, unsigned int unused = 0 )
00097             :required(lsize)
00098         {
00099             for(unsigned int i=0; i <lsize; ++i)
00100                 mreserved.push(new Cont());
00101         }
00102 
00103         ~ListLocked() {
00104             this->clear();
00105             while( !mreserved.empty() ) {
00106                 delete mreserved.top();
00107                 mreserved.pop();
00108             }
00109         }
00110 
00111         size_t capacity() const
00112         {
00113             os::MutexLock lock(m);
00114             return mreserved.size() + mlist.size();
00115         }
00116 
00117         size_t size() const
00118         {
00119             os::MutexLock lock(m);
00120             return mlist.size();
00121         }
00122 
00123         bool empty() const
00124         {
00125             os::MutexLock lock(m);
00126             return mlist.empty();
00127         }
00128 
00136         void grow(size_t items = 1) {
00137             os::MutexLock lock(m);
00138             required += items;
00139             if (required > mreserved.size() + mlist.size() ) {
00140                 while ( mreserved.size() + mlist.size() < required * 2) {
00141                     mreserved.push( new Cont() );
00142                 }
00143             }
00144         }
00152         void shrink(size_t items = 1) {
00153             os::MutexLock lock(m);
00154             required -= items;
00155         }
00156 
00163         void reserve(size_t lsize)
00164         {
00165             os::MutexLock lock(m);
00166             while ( mreserved.size() + mlist.size() < lsize) {
00167                 mreserved.push( new Cont() );
00168             }
00169         }
00170 
00171         void clear()
00172         {
00173             os::MutexLock lock(m);
00174             mlist.clear_and_dispose( boost::bind(&ListLocked::give_back, this, _1) );
00175         }
00176 
00182         bool append( value_t item )
00183         {
00184             os::MutexLock lock(m);
00185             if ( mreserved.empty() )
00186                 return false;
00187             mlist.push_back( this->get_item(item) );
00188             return true;
00189         }
00190 
00194         value_t front() const
00195         {
00196             os::MutexLock lock(m);
00197             return mlist.front().data;
00198         }
00199 
00203         value_t back() const
00204         {
00205             os::MutexLock lock(m);
00206             return mlist.back().data;
00207         }
00208 
00214         size_t append(const std::vector<T>& items)
00215         {
00216             os::MutexLock lock(m);
00217             unsigned int max = mreserved.size();
00218             typename std::vector<T>::const_iterator it = items.begin();
00219             for(; it != items.end() && max != 0; ++it, --max )
00220                 mlist.push_back( this->get_item(*it) );
00221             return it - items.begin();
00222         }
00223 
00224 
00230         bool erase( value_t item )
00231         {
00232             os::MutexLock lock(m);
00233             mlist.remove_and_dispose_if( boost::bind(&ListLocked::is_item, this, item, _1), boost::bind(&ListLocked::give_back, this, _1) );
00234             return true;
00235         }
00236 
00244         template<typename Pred>
00245         bool delete_if(Pred pred)
00246         {
00247             os::MutexLock lock(m);
00248             bool deleted = false;
00249 
00250             typename BufferType::iterator cur(mlist.begin());
00251             typename BufferType::iterator last(mlist.end());
00252 
00253             while(cur != last) 
00254             {
00255             if(pred(cur->data))
00256             {
00257                 cur = mlist.erase_and_dispose(cur, boost::bind(&ListLocked::give_back, this, ::_1) );
00258                 deleted = true;
00259             }
00260             else
00261                 ++cur;
00262             }
00263 
00264             return deleted;
00265         }
00266 
00273         template<class Function>
00274         void apply(Function func )
00275         {
00276             os::MutexLock lock(m);
00277             // A free beer for the one that can express this with a for_each construct.
00278             for (Iterator it = mlist.begin(); it != mlist.end(); ++it)
00279                 func( it->data );
00280         }
00281 
00287         template<class Function>
00288         value_t find_if( Function func, value_t blank = value_t() )
00289         {
00290             os::MutexLock lock(m);
00291             Iterator it = std::find_if(mlist.begin(), mlist.end(), boost::bind(func, boost::bind(&ListLocked::get_data, this,_1)));
00292             if (it != mlist.end() )
00293                 return it->data;
00294             return blank;
00295         }
00296     private:
00302         void give_back(Cont* cont)
00303         {
00304             mreserved.push( cont );
00305         }
00306 
00307         Cont& get_item(value_t item)
00308         {
00309             Cont* c = mreserved.top();
00310             mreserved.pop();
00311             c->data = item;
00312             return *c;
00313         }
00314 
00315         value_t& get_data(Cont& c)
00316         {
00317             return c.data;
00318         }
00319 
00327         bool is_item(value_t item, const Cont& cont)
00328         {
00329             return item == cont.data;
00330         }
00331     };
00332 
00333 }}
00334 
00335 #endif