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

Generated on Tue Aug 25 14:17:23 2009 for Orocos Real-Time Toolkit by  doxygen 1.5.8