SingleList.hpp

00001 /***************************************************************************
00002   tag: Peter Soetens  Wed Jan 18 14:11:39 CET 2006  SingleList.hpp
00003 
00004                         SingleList.hpp -  description
00005                            -------------------
00006     begin                : Wed January 18 2006
00007     copyright            : (C) 2006 Peter Soetens
00008     email                : peter.soetens@mech.kuleuven.be
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_SINGLE_LIST_HPP
00040 #define ORO_SINGLE_LIST_HPP
00041 
00042 #include "os/CAS.hpp"
00043 #include <boost/shared_ptr.hpp>
00044 #include "MemoryPool.hpp"
00045 
00046 namespace RTT
00047 {
00064     template<class DataType_>
00065     class SingleList
00066     {
00067     public:
00068         typedef DataType_ DataType;
00069     protected:
00070         struct NodeType
00071         {
00072             typedef NodeType* NodeType_sptr;
00073             DataType key;
00074             NodeType_sptr next;
00075 
00076             NodeType(const DataType& data)
00077                 : key(data)
00078             {}
00079 
00080             NodeType()
00081                 : key()
00082             {}
00083         };
00084 
00088         typedef NodeType Node;
00092         typedef typename NodeType::NodeType_sptr Node_sptr;
00093 
00094         MemoryPool<Node> mpool;
00095 
00096         Node_sptr head;
00097         Node_sptr tail;
00098 
00099         Node_sptr searchKey(const DataType& search_key, Node_sptr& left_node)
00100         {
00101             Node_sptr left_node_next, right_node;
00102         search_again:
00103             do {
00104                 Node_sptr t = this->head;
00105                 Node_sptr t_next = this->head->next;
00106 
00107                 do {
00108                     if (!is_marked_reference(t_next)) {
00109                         left_node = t;
00110                         left_node_next = t_next;
00111                     }
00112                     t = get_unmarked_reference(t_next);
00113                     if (t == this->tail)
00114                         break;
00115                     t_next = t->next;
00116                     // search as long as key is not found, or end is not reached.
00117                 } while ( is_marked_reference(t_next) ||
00118                           !(t->key == search_key ||
00119                             t == this->tail));
00120                 right_node = t;
00121 
00122                 if (left_node_next == right_node)
00123                     if ((right_node != this->tail) && is_marked_reference(right_node->next))
00124                         goto search_again;
00125                     else
00126                         return right_node;
00127 
00128                 if (OS::CAS(&(left_node->next), left_node_next, right_node)) {
00129                     mpool.deallocate( get_unmarked_reference(left_node_next) );
00130                     if ((right_node != this->tail) && is_marked_reference(right_node->next))
00131                         goto search_again;
00132                     else
00133                         return right_node;
00134                 }
00135             } while (true);
00136         }
00137 
00138         // apply.
00139         template< class F>
00140         Node_sptr searchEnd(const F& foo, Node_sptr& left_node)
00141         {
00142             Node_sptr left_node_next;
00143             // start one after head.
00144             Node_sptr t = this->head->next;
00145             Node_sptr t_next = t->next;
00146 
00147             if ( t == tail ) {
00148                 left_node = head;
00149                 return tail;
00150             }
00151 
00152             do {
00153                 DataType data( t->key );
00154                 if (!is_marked_reference(t_next)) {
00155                     left_node = t;
00156                     left_node_next = t_next;
00157                     //if (!is_marked_reference( t_next ) ) // check *again* for invalidation.
00158                     foo( data ); // apply on copy.
00159                 }
00160                 t = get_unmarked_reference(t_next);
00161                 if (t == this->tail)
00162                     break;
00163                 t_next = t->next;
00164                 // search as long as end is not reached.
00165             } while ( is_marked_reference(t_next) ||
00166                       t != this->tail );
00167             // t == tail.
00168 
00169             return t;
00170         }
00171 
00172         bool is_marked_reference(Node* n)
00173         {
00174             unsigned int v = reinterpret_cast<unsigned int>(n);
00175             return (v%2) == 1;
00176         }
00177 
00178         Node* get_unmarked_reference(Node* n)
00179         {
00180             unsigned int v = reinterpret_cast<unsigned int>(n);
00181             return reinterpret_cast<Node*>( v & -2 ); // is ..11110
00182         }
00183 
00184         Node* get_marked_reference(Node* n)
00185         {
00186             unsigned int v = reinterpret_cast<unsigned int>(n);
00187             return reinterpret_cast<Node*>( v | 1);  // is ...00001
00188         }
00189     public:
00190 
00194         SingleList()
00195         {
00196             mpool.reserve();
00197             mpool.reserve();
00198             head = mpool.allocate();
00199             tail = mpool.allocate();
00200 
00201             head->next = tail;
00202         }
00203 
00204         ~SingleList()
00205         {
00206             mpool.deallocate(head);
00207             mpool.deallocate(tail);
00208         }
00209 
00213         void reserve(size_t n = 1)
00214         { size_t i(0); while (i++ < n) mpool.reserve(); }
00215 
00219         void shrink(size_t n = 1)
00220         { size_t i(0); while (i++ < n) mpool.shrink(); }
00221 
00225         bool empty() const
00226         {
00227             return head->next == tail;
00228         }
00229 
00235         bool insert(const DataType& key)
00236         {
00237             Node_sptr new_node( mpool.allocate() );
00238             Node_sptr right_node, left_node;
00239 
00240             new_node->key = key;
00241             do {
00242                 right_node = this->searchKey(key, left_node);
00243                 if ((right_node != tail) && (right_node->key == key )) {
00244                     mpool.deallocate( new_node );
00245                     return false;
00246                 }
00247                 new_node->next = right_node;
00248                 if (OS::CAS(&(left_node->next), right_node, new_node))
00249                     return true;
00250             } while (true);
00251         }
00252 
00258         bool erase(const DataType& search_key)
00259         {
00260             Node_sptr right_node, right_node_next, left_node;
00261 
00262             do {
00263                 right_node = searchKey(search_key, left_node);
00264                 if (( right_node == tail) || !(right_node->key == search_key) )
00265                     return false;
00266                 right_node_next = right_node->next;
00267                 if (!is_marked_reference(right_node_next))
00268                     if (OS::CAS( &(right_node->next), right_node_next, get_marked_reference(right_node_next)))
00269                         break;
00270             } while(true);
00271             if (!OS::CAS(&(left_node->next), right_node, right_node_next))
00272                 right_node = search(right_node->key, left_node);
00273             else
00274                 mpool.deallocate( get_unmarked_reference(right_node) );
00275             return true;
00276         }
00277 
00283         bool hasKey(const DataType& search_key)
00284         {
00285             Node_sptr right_node, left_node;
00286 
00287             right_node = searchKey( search_key, left_node);
00288             if ((right_node == tail) || !(right_node->key == search_key))
00289                 return false;
00290             else
00291                 return true;
00292         }
00293 
00308         template<class Function>
00309         void applyOnData(const Function& f )
00310         {
00311             // start at head, go until tail. This is similar to search().
00312             Node_sptr t = this->head;
00313             Node_sptr t_next = this->head->next;
00314 
00315             // Marked fields may be traversed !
00316             // thus go on until you hit the tail.
00317             do {
00318                 // need to unmark always to be sure.
00319                 t = get_unmarked_reference(t_next);
00320                 if (t == this->tail)
00321                     return;
00322                 if (!is_marked_reference(t_next)) {
00323                     // The applying conseptually starts here. If t_next is now concurrently erased,
00324                     // f() was already in progress of execution, so it continues.
00325                     f( t->key );
00326                 }
00327                 t_next = t->next;
00328             } while ( true );
00329 
00330         }
00331 
00339         template<class Function>
00340         void applyOnCopy(const Function& f )
00341         {
00342             // start at head, go until tail. This is similar to search().
00343             Node_sptr t;
00344             Node_sptr t_next = this->head->next;
00345 
00346             // Marked fields may be traversed !
00347             // thus go on until you hit the tail.
00348             do {
00349                 // need to unmark always to be sure.
00350                 t = get_unmarked_reference(t_next);
00351                 if (t == this->tail)
00352                     return;
00353                 // make the copy
00354                 DataType d(t->key);
00355                 if (!is_marked_reference(t_next)) {
00356                     // The applying conseptually starts here. If t_next is now concurrently erased,
00357                     // f() was already in progress of execution, so it continues.
00358                     f( d );
00359                 }
00360                 t_next = t->next;
00361             } while ( true );
00362 
00363         }
00364     };
00365 
00366 }
00367 
00368 #endif
Generated on Thu Dec 23 13:22:38 2010 for Orocos Real-Time Toolkit by  doxygen 1.6.3