SortedList.hpp

00001 /***************************************************************************
00002   tag: Peter Soetens  Wed Jan 18 14:11:39 CET 2006  SortedList.hpp
00003 
00004                         SortedList.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_SORTED_LIST_HPP
00040 #define ORO_SORTED_LIST_HPP
00041 
00042 #include "os/CAS.hpp"
00043 #include <boost/shared_ptr.hpp>
00044 #include "MemoryPool.hpp"
00045 
00046 namespace RTT
00047 {
00062     template<class DataType_>
00063     class SortedList
00064     {
00065     public:
00066         typedef DataType_ DataType;
00067     protected:
00068         struct NodeType
00069         {
00070             typedef NodeType* NodeType_sptr;
00071             DataType key;
00072             NodeType_sptr next;
00073 
00074             NodeType(const DataType& data)
00075                 : key(data)
00076             {}
00077 
00078             NodeType()
00079                 : key()
00080             {}
00081         };
00082 
00086         typedef NodeType Node;
00090         typedef typename NodeType::NodeType_sptr Node_sptr;
00091 
00092         MemoryPool<Node> mpool;
00093 
00094         Node_sptr head;
00095         Node_sptr tail;
00096 
00097         Node_sptr search(const DataType& search_key, Node_sptr& left_node)
00098         {
00099             Node_sptr left_node_next, right_node;
00100         search_again:
00101             do {
00102                 Node_sptr t = this->head;
00103                 Node_sptr t_next = this->head->next;
00104 
00105                 do {
00106                     if (!is_marked_reference(t_next)) {
00107                         left_node = t;
00108                         left_node_next = t_next;
00109                     }
00110                     t = get_unmarked_reference(t_next);
00111                     if (t == this->tail)
00112                         break;
00113                     t_next = t->next;
00114                 } while (is_marked_reference(t_next) || (t->key < search_key));
00115                 right_node = t;
00116 
00117                 if (left_node_next == right_node)
00118                     if ((right_node != this->tail) && is_marked_reference(right_node->next))
00119                         goto search_again;
00120                     else
00121                         return right_node;
00122 
00123                 if (OS::CAS(&(left_node->next), left_node_next, right_node)) {
00124                     mpool.deallocate( get_unmarked_reference(left_node_next) );
00125                     if ((right_node != this->tail) && is_marked_reference(right_node->next))
00126                         goto search_again;
00127                     else
00128                         return right_node;
00129                 }
00130             } while (true);
00131         }
00132 
00133         bool is_marked_reference(Node* n)
00134         {
00135             unsigned int v = reinterpret_cast<unsigned int>(n);
00136             return (v%2) == 1;
00137         }
00138 
00139         Node* get_unmarked_reference(Node* n)
00140         {
00141             unsigned int v = reinterpret_cast<unsigned int>(n);
00142             return reinterpret_cast<Node*>( v & -2 ); // is ..11110
00143         }
00144 
00145         Node* get_marked_reference(Node* n)
00146         {
00147             unsigned int v = reinterpret_cast<unsigned int>(n);
00148             return reinterpret_cast<Node*>( v | 1);  // is ...00001
00149         }
00150     public:
00151 
00155         SortedList()
00156         {
00157             mpool.reserve();
00158             mpool.reserve();
00159             head = mpool.allocate();
00160             tail = mpool.allocate();
00161 
00162             head->next = tail;
00163         }
00164 
00165         ~SortedList()
00166         {
00167             mpool.deallocate(head);
00168             mpool.deallocate(tail);
00169         }
00170 
00174         void reserve(size_t n = 1)
00175         { size_t i(0); while (i++ < n) mpool.reserve(); }
00176 
00180         void shrink(size_t n = 1)
00181         { size_t i(0); while (i++ < n) mpool.shrink(); }
00182 
00186         bool empty() const
00187         {
00188             return head->next == tail;
00189         }
00190 
00196         bool insert(const DataType& key)
00197         {
00198             Node_sptr new_node( mpool.allocate() );
00199             Node_sptr right_node, left_node;
00200 
00201             new_node->key = key;
00202             do {
00203                 right_node = this->search(key, left_node);
00204                 if ((right_node != tail) && (right_node->key == key )) {
00205                     mpool.deallocate( new_node );
00206                     return false;
00207                 }
00208                 new_node->next = right_node;
00209                 if (OS::CAS(&(left_node->next), right_node, new_node))
00210                     return true;
00211             } while (true);
00212         }
00213 
00219         bool erase(const DataType& search_key)
00220         {
00221             Node_sptr right_node, right_node_next, left_node;
00222 
00223             do {
00224                 right_node = search(search_key, left_node);
00225                 if (( right_node == tail) || !(right_node->key == search_key) )
00226                     return false;
00227                 right_node_next = right_node->next;
00228                 if (!is_marked_reference(right_node_next))
00229                     if (OS::CAS( &(right_node->next), right_node_next, get_marked_reference(right_node_next)))
00230                         break;
00231             } while(true);
00232             if (!OS::CAS(&(left_node->next), right_node, right_node_next))
00233                 right_node = search(right_node->key, left_node);
00234             else
00235                 mpool.deallocate( get_unmarked_reference(right_node) );
00236             return true;
00237         }
00238 
00244         bool hasKey(const DataType& search_key)
00245         {
00246             Node_sptr right_node, left_node;
00247 
00248             right_node = search( search_key, left_node);
00249             if ((right_node == tail) || !(right_node->key == search_key))
00250                 return false;
00251             else
00252                 return true;
00253         }
00254 
00269         template<class Function>
00270         void applyOnData(const Function& f )
00271         {
00272             // start at head, go until tail. This is similar to search().
00273             Node_sptr t = this->head;
00274             Node_sptr t_next = this->head->next;
00275 
00276             // Marked fields may be traversed !
00277             // thus go on until you hit the tail.
00278             do {
00279                 // need to unmark always to be sure.
00280                 t = get_unmarked_reference(t_next);
00281                 if (t == this->tail)
00282                     return;
00283                 if (!is_marked_reference(t_next)) {
00284                     // The applying conseptually starts here. If t_next is now concurrently erased,
00285                     // f() was already in progress of execution, so it continues.
00286                     f( t->key );
00287                 }
00288                 t_next = t->next;
00289             } while ( true );
00290 
00291         }
00292 
00300         template<class Function>
00301         void applyOnCopy(const Function& f )
00302         {
00303             // start at head, go until tail. This is similar to search().
00304             Node_sptr t;
00305             Node_sptr t_next = this->head->next;
00306 
00307             // Marked fields may be traversed !
00308             // thus go on until you hit the tail.
00309             do {
00310                 // need to unmark always to be sure.
00311                 t = get_unmarked_reference(t_next);
00312                 if (t == this->tail)
00313                     return;
00314                 // make the copy
00315                 DataType d(t->key);
00316                 if (!is_marked_reference(t_next)) {
00317                     // The applying conseptually starts here. If t_next is now concurrently erased,
00318                     // f() was already in progress of execution, so it continues.
00319                     f( d );
00320                 }
00321                 t_next = t->next;
00322             } while ( true );
00323 
00324         }
00325     };
00326 
00327 }
00328 
00329 #endif
Generated on Thu Dec 23 13:22:38 2010 for Orocos Real-Time Toolkit by  doxygen 1.6.3