w_list.h

Go to the documentation of this file.
00001 /* -*- mode:C++; c-basic-offset:4 -*-
00002      Shore-MT -- Multi-threaded port of the SHORE storage manager
00003    
00004                        Copyright (c) 2007-2009
00005       Data Intensive Applications and Systems Labaratory (DIAS)
00006                Ecole Polytechnique Federale de Lausanne
00007    
00008                          All Rights Reserved.
00009    
00010    Permission to use, copy, modify and distribute this software and
00011    its documentation is hereby granted, provided that both the
00012    copyright notice and this permission notice appear in all copies of
00013    the software, derivative works or modified versions, and any
00014    portions thereof, and that both notices appear in supporting
00015    documentation.
00016    
00017    This code is distributed in the hope that it will be useful, but
00018    WITHOUT ANY WARRANTY; without even the implied warranty of
00019    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS
00020    DISCLAIM ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER
00021    RESULTING FROM THE USE OF THIS SOFTWARE.
00022 */
00023 
00024 /*<std-header orig-src='shore' incl-file-exclusion='W_LIST_H'>
00025 
00026  $Id: w_list.h,v 1.55 2010/06/21 20:39:24 nhall Exp $
00027 
00028 SHORE -- Scalable Heterogeneous Object REpository
00029 
00030 Copyright (c) 1994-99 Computer Sciences Department, University of
00031                       Wisconsin -- Madison
00032 All Rights Reserved.
00033 
00034 Permission to use, copy, modify and distribute this software and its
00035 documentation is hereby granted, provided that both the copyright
00036 notice and this permission notice appear in all copies of the
00037 software, derivative works or modified versions, and any portions
00038 thereof, and that both notices appear in supporting documentation.
00039 
00040 THE AUTHORS AND THE COMPUTER SCIENCES DEPARTMENT OF THE UNIVERSITY
00041 OF WISCONSIN - MADISON ALLOW FREE USE OF THIS SOFTWARE IN ITS
00042 "AS IS" CONDITION, AND THEY DISCLAIM ANY LIABILITY OF ANY KIND
00043 FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
00044 
00045 This software was developed with support by the Advanced Research
00046 Project Agency, ARPA order number 018 (formerly 8230), monitored by
00047 the U.S. Army Research Laboratory under contract DAAB07-91-C-Q518.
00048 Further funding for this work was provided by DARPA through
00049 Rome Research Laboratory Contract No. F30602-97-2-0247.
00050 
00051 */
00052 
00053 #ifndef W_LIST_H
00054 #define W_LIST_H
00055 
00056 #include "w_defines.h"
00057 
00058 /*  -- do not edit anything above this line --   </std-header>*/
00059 
00060 #ifndef W_BASE_H
00061 #include <w_base.h>
00062 #endif
00063 
00064 #include <iostream>
00065 
00066 /**\file w_list.h
00067  *
00068  * This file contains class definitions for linked lists of
00069  * various kinds.
00070  */
00071 
00072 class w_list_base_t;
00073 template <class T, class LOCK> class w_list_t;
00074 template <class T, class LOCK> class w_list_i;
00075 template <class T, class LOCK, class K> class w_hash_t;
00076 
00077 /**\brief You can instantiate unsafe lists by using this type.
00078  * \details
00079  * This makes it relatively easy to grep for the unsafe lists in
00080  * the system.
00081  * \note There is no automagic enforcement of locking for w_list_t
00082  * w_hash_t or anything based on them.
00083  * Their templates just require a lock type so we can easily
00084  * find those that are locked in the code somewhere, somehow, and
00085  * those that are not.
00086  */
00087 class unsafe_list_dummy_lock_t
00088 {};
00089 unsafe_list_dummy_lock_t* const unsafe_nolock=NULL; // instantiate with this 
00090 
00091 
00092 /**\brief Link structure for membership in any class to be put on a w_list*
00093  *
00094  * Classes that will always be on one or more lists may contain a member
00095  * of type w_link_t. This contains the \b next and \b prev pointers
00096  * for putting the class instance into a doubly-linked list. 
00097  *
00098  * Embedding the w_link_t structures in the objects to be linked together
00099  * into a list avoids heap activity for list insertion and removal.
00100  */
00101 class w_link_t {
00102 public:
00103     NORET            w_link_t();
00104     NORET            ~w_link_t();
00105     NORET            w_link_t(const w_link_t&);
00106     w_link_t&             operator=(const w_link_t&);
00107 
00108     /// insert object containing this link into the list of
00109     /// which prev_link is a member. Insert after prev_link.
00110     void            attach(w_link_t* prev_link);
00111     void            check() {
00112                         w_assert9(_prev == this && _next == this); // not in a list
00113                     }
00114     /// remove containing object from the list.
00115     w_link_t*       detach();
00116     w_list_base_t*  member_of() const;
00117 
00118     w_link_t*       next() const;
00119     w_link_t*       prev() const;
00120 
00121 private:
00122     w_list_base_t*        _list;
00123     w_link_t*            _next;
00124     w_link_t*            _prev;
00125 
00126     friend class w_list_base_t;
00127 };
00128 
00129 /**\brief Base class for various list classes.
00130  *
00131  */
00132 class w_list_base_t : public w_vbase_t {
00133     
00134 public:
00135     bool             is_empty() const;
00136     uint4_t          num_members() const;
00137 
00138     void             dump();
00139 protected:
00140     NORET            w_list_base_t();
00141     NORET            w_list_base_t(uint4_t offset);
00142     NORET            ~w_list_base_t();
00143 
00144     void            set_offset(uint4_t offset);
00145     
00146     w_link_t            _tail;
00147     uint4_t            _cnt;
00148     uint4_t            _adj;
00149 
00150 private:
00151     NORET            w_list_base_t(w_list_base_t&); // disabled
00152     w_list_base_t&        operator=(w_list_base_t&);
00153     
00154     friend class w_link_t;
00155 };
00156 
00157 inline NORET
00158 w_link_t::w_link_t()
00159 : _list(0) 
00160 {
00161     _next = this;
00162     _prev = this;
00163     /* empty body */
00164 }
00165 
00166 inline NORET
00167 w_link_t::~w_link_t()
00168 {
00169     w_assert1(_next == this && _prev == this && _list == 0);
00170 }
00171 
00172 inline NORET
00173 w_link_t::w_link_t(const w_link_t&)
00174 : _list(0)
00175 {
00176     _next = _prev = this;
00177 }
00178 
00179 inline w_link_t&
00180 w_link_t::operator=(const w_link_t&)
00181 {
00182     _list = 0;
00183     return *(_next = _prev = this);
00184 }
00185 
00186 inline w_list_base_t*
00187 w_link_t::member_of() const
00188 {
00189     return _list;
00190 }
00191 
00192 inline w_link_t*
00193 w_link_t::prev() const
00194 {
00195     return _prev;
00196 }
00197 
00198 inline w_link_t*
00199 w_link_t::next() const
00200 {
00201     return _next;
00202 }
00203 
00204 inline NORET
00205 w_list_base_t::w_list_base_t()
00206     : _cnt(0), _adj(uint4_max)  // _adj must be set by a later call
00207                 // to set_offset().  We init _adj
00208                 // with a large number to detect
00209                 // errors
00210 {
00211     _tail._list = 0;
00212     w_assert9(_tail._next == &_tail && _tail._prev == &_tail);
00213 }
00214 
00215 inline NORET
00216 w_list_base_t::w_list_base_t(uint4_t offset)
00217     : _cnt(0), _adj(offset)
00218 {
00219     _tail._list = this;
00220     w_assert9(_tail._next == &_tail && _tail._prev == &_tail);
00221 }
00222 
00223 inline void 
00224 w_list_base_t::set_offset(uint4_t offset)
00225 {
00226     w_assert9(_cnt == 0 && _adj == uint4_max && _tail._list == 0);
00227     _tail._list = this;
00228     _adj = offset;
00229 }
00230 
00231 inline NORET
00232 w_list_base_t::~w_list_base_t()
00233 {
00234   _tail._list = 0;
00235     w_assert9(_cnt == 0);
00236 }
00237 
00238 inline bool
00239 w_list_base_t::is_empty() const
00240 {
00241     return _cnt == 0;
00242 }
00243 
00244 inline w_base_t::uint4_t
00245 w_list_base_t::num_members() const
00246 {
00247     return _cnt;
00248 }
00249 
00250 template <class T, class L> class w_list_t;
00251 
00252 BIND_FRIEND_OPERATOR_PART_1(T, L, w_list_t<T,L>)
00253     
00254 /**\brief Templated list of type T.
00255  *
00256  * \attention These lists are not thread-safe.
00257  * The user must provide the locks to access the lists
00258  * if thread-safety is necessary.
00259  * In order to identify the locations of all these, I am
00260  * adding a template type for the lock, and I'm going
00261  * to assert lock.is_mine, at least in debugging mode.
00262  */
00263 template <class T, class LOCK>
00264 class w_list_t : public w_list_base_t {
00265 protected:
00266     /// return non-const ptr to link member of
00267     /// an object in this list
00268     w_link_t*             link_of(T* t) {
00269         w_assert3(t);
00270         return CAST(w_link_t*, CAST(char*,t)+_adj);
00271     }
00272 
00273     /// const version of the above
00274     const w_link_t*         link_of(const T* t) const {
00275         w_assert3(t);
00276         return CAST(w_link_t*, CAST(char*,t)+_adj);
00277     }
00278 
00279     /// return object of which the given link is a member
00280     T*                 base_of(w_link_t* p) const {
00281         w_assert3(p);
00282         return CAST(T*, CAST(char*, p) - _adj);
00283     }
00284 
00285     /// const version of the above
00286     const T*             base_of(const w_link_t* p) const {
00287         w_assert3(p);
00288         return CAST(T*, CAST(char*, p) - _adj);
00289     }
00290 
00291 private:
00292     LOCK *lock;
00293 public:
00294 
00295     /**\brief Linked list constructor.
00296      * \details
00297      * @param[in] link_offset Offset into type T of the w_link_t used
00298      * for this list.
00299      * @param[in] l Pointer to the lock that will protect this list.
00300      *
00301      * \note These lists are not locked; it is up to the client to 
00302      * provide synchronization for the list.  The LOCK template argument
00303      * is solely to make the list uses somewhat self-documenting.
00304      * By code perusal you might be able to tell what lock type and
00305      * what lock is meant to protect this list.
00306      *
00307      */
00308     NORET            w_list_t(uint4_t link_offset, LOCK *l)
00309     : w_list_base_t(link_offset), lock(l)
00310     {
00311 #ifdef __GNUC__
00312 #else
00313         w_assert2(link_offset + sizeof(w_link_t) <= sizeof(T));
00314 #endif
00315     }
00316 
00317 public:
00318     /// create a list sans offset.  Client must use set_offset later,
00319     ///before using the list.
00320     // This is used by w_hash_t  and the lock manager's list of lock heads
00321     NORET            w_list_t() : lock(NULL) {}
00322 
00323 public:
00324 
00325     NORET            ~w_list_t() {}
00326 
00327     /// Tell the list where to find the offset of the w_link_t in 
00328     /// the item-type T.
00329     /// Lists constructed with the vacuous constructor \b must
00330     /// have this called before the list is used.
00331     void             set_offset(uint4_t link_offset) {
00332                         w_list_base_t::set_offset(link_offset);
00333     }
00334 
00335     /// For ordered lists, this uses the ordering. For unordered
00336     /// lists (simply w_list_t<T,LOCK>), it just inserts.
00337     virtual void        put_in_order(T* t)  {
00338         w_list_t<T,LOCK>::push(t);
00339     }
00340 
00341     // a set of consistent and intuitive names
00342     // TODO: replace throughout the SM
00343     w_list_t<T,LOCK>&   push_front(T* t) { return push(t); }
00344     w_list_t<T,LOCK>&   push_back (T* t) { return append(t); }
00345     T*  front() { return top(); }
00346     T*  back()  { return bottom(); }
00347     T*  pop_front() { return pop(); }
00348     T*  pop_back()  { return chop(); }
00349     
00350     /// Insert 
00351     w_list_t<T,LOCK>&   push(T* t)   {
00352         link_of(t)->attach(&_tail);
00353         return *this;
00354     }
00355 
00356     /// Insert at tail
00357     w_list_t<T,LOCK>&   append(T* t) {
00358         link_of(t)->attach(_tail.prev());
00359         return *this;
00360     }
00361 
00362     /// Remove
00363     T*                  pop()   {
00364         return _cnt ? base_of(_tail.next()->detach()) : 0;
00365     }
00366 
00367     /// Remove from rear
00368     T*                  chop()  {
00369         return _cnt ? base_of(_tail.prev()->detach()) : 0;
00370     }
00371 
00372     /// Get first but don't remove
00373     T*                  top()   {
00374         return _cnt ? base_of(_tail.next()) : 0;
00375     }
00376 
00377     /// Get last but don't remove
00378     T*                  bottom(){
00379         return _cnt ? base_of(_tail.prev()) : 0;
00380     }
00381 
00382     /// Get next
00383     T*                next(w_link_t* p) {
00384         w_assert1(p->member_of() == this);
00385         return base_of(p->next());
00386     }
00387 
00388     /// Get prev
00389     T*                prev(w_link_t* p) {
00390         w_assert1(p->member_of() == this);
00391         return base_of(p->prev());
00392     }
00393 
00394     /// streams output
00395     friend ostream&        operator<< BIND_FRIEND_OPERATOR_PART_2(T, LOCK) (
00396         ostream&             o,
00397         const w_list_t<T,LOCK>&         l);
00398 
00399 private:
00400     // disabled
00401     NORET                  w_list_t(const w_list_t<T,LOCK>&x) ;
00402     w_list_t<T,LOCK>&      operator=(const w_list_t<T,LOCK>&) ;
00403     
00404     friend class w_list_i<T, LOCK>;
00405 };
00406 
00407 /// Macro used to name the member of the object that is the link
00408 #define    W_LIST_ARG(class,member)    w_offsetof(class,member)
00409 
00410 
00411 /**\brief Iterator for a list.
00412  *
00413  * \attention This iterator is not thread-safe. It is up to the user to
00414  * provide thread-safety for the list.
00415  *
00416  * \attention Modifying the list while iterating over it: 
00417  * You can remove items from the list while iterating over it thus:
00418  * \code
00419  * while(iter.next()) {
00420  *    item = iter.curr();
00421  *    < Now you can remove the item. >
00422  * }
00423  * \endcode
00424  * Adding elements to the list while iterating yields undefined behavior.
00425  *
00426  * Example of use:
00427  * \code
00428  * w_list_t<sthread_t*> thread_list;
00429  * w_list_i<sthread_t*> i(thread_list);
00430  *
00431  * while(i.next()) {
00432  *    sthread_t *t = i.curr();
00433  *    if (t-> .....) ....
00434  * }
00435  * \endcode
00436  */
00437 template <class T, class LOCK>
00438 class w_list_i : public w_base_t {
00439 public:
00440     /// Create a forward iterator. Since the list to be iterated
00441     /// isn't given, you must call reset() before you can use this
00442     ///iterator.
00443     NORET            w_list_i()
00444     : _list(0), _next(0), _curr(0), _backwards(false)        {};
00445 
00446     /// Create a forward or backward iterator iterator for the given
00447     /// list. Don't allow updating of the list while iterating.
00448     NORET            w_list_i(const w_list_t<T,LOCK>& l, bool backwards = false)
00449     :   _list(&l), _curr(0), _backwards(backwards) {
00450         _next = (backwards ? l._tail.prev() : l._tail.next());
00451     }
00452 
00453     NORET            ~w_list_i()    {};
00454 
00455     /// Make an iterator usable (possibly again), for the given list,
00456     /// backward or forward.
00457     void            reset(const w_list_t<T, LOCK>& l, bool backwards = false)  {
00458         _list = &l;
00459         _curr = 0;
00460         _backwards = backwards;
00461         _next = (_backwards ? l._tail.prev() : l._tail.next());
00462     }
00463     
00464     /// Adjust the iterator to point to the next item in the list and return 
00465     /// a pointer to that next item.
00466     /// Returns NULL if there is no next item.
00467     /// Note that this depends on the results of the previous next() call,
00468     /// but what we do with curr() from the prior call is immaterial.
00469     T*                next()     
00470     {
00471         if (_next)  {
00472             _curr = (_next == &(_list->_tail)) ? 0 : _list->base_of(_next);
00473             _next = (_backwards ? _next->prev() : _next->next());
00474             // Note: once we ever had anything in the list, next() will
00475             // be non-null. We will return NULL when _curr hits the tail.
00476             // _next can be null only if we started with an empty list.
00477             w_assert1(_next != NULL);
00478         }
00479         return _curr;
00480     }
00481 
00482     /**\brief Return the current item in the list.
00483      * \details
00484      * Returns NULL if there is no current item.
00485      * There is no current item until next() is called at
00486      * least once, thus, one must call next() to get the first item.
00487      */
00488     T*                curr() const  {
00489         return _curr;
00490     }
00491     
00492 protected: 
00493     const w_list_t<T, LOCK>*        _list;
00494 private:
00495     w_link_t*           _next;
00496     T*                  _curr;
00497     bool                _backwards;
00498 
00499     // disabled
00500     NORET               w_list_i(w_list_i<T, LOCK>&) ;
00501     w_list_i<T, LOCK>&        operator=(w_list_i<T, LOCK>&) ;
00502 };
00503 
00504 
00505 /**\brief Const iterator for a list.
00506  *
00507  * A const version of w_list_i.  The pointers it
00508  * returns are const pointers to list members.
00509  */
00510 template <class T, class LOCK>
00511 class w_list_const_i : public w_list_i<T, LOCK> {
00512 public:
00513     NORET            w_list_const_i()  {};
00514     NORET            w_list_const_i(const w_list_t<T,LOCK>& l)
00515                         : w_list_i<T,LOCK>(* (w_list_t<T,LOCK>*)(&l))    {};
00516     NORET            ~w_list_const_i() {};
00517     
00518     void            reset(const w_list_t<T,LOCK>& l) {
00519         w_list_i<T,LOCK>::reset(* (w_list_t<T,LOCK>*) (&l));
00520     }
00521 
00522     const T*            next() { return w_list_i<T,LOCK>::next(); }
00523     const T*            curr() const { 
00524         return w_list_i<T,LOCK>::curr(); 
00525     }
00526 private:
00527     // disabled
00528     NORET            w_list_const_i(w_list_const_i<T,LOCK>&);
00529     w_list_const_i<T,LOCK>&        operator=(w_list_const_i<T,LOCK>&);
00530 };
00531 
00532 /**\brief Base class for sorted lists.
00533  *
00534  * T is the type of the objects going into the list.
00535  * K is the type of the key for sorting.
00536  */
00537 template <class T, class LOCK, class K>
00538 class w_keyed_list_t : public w_list_t<T,LOCK> {
00539 public:
00540     T*                first() { return w_list_t<T,LOCK>::top(); }
00541     T*                last()  { return w_list_t<T,LOCK>::bottom(); }
00542     virtual T*            search(const K& k);
00543 
00544     NORET            w_keyed_list_t(LOCK *lock);
00545     NORET            w_keyed_list_t(
00546                         w_base_t::uint4_t        key_offset,
00547                         w_base_t::uint4_t        link_offset,
00548                         LOCK *                   lock 
00549                         );
00550 
00551     NORET            ~w_keyed_list_t()    {};
00552 
00553     void            set_offset(
00554                         w_base_t::uint4_t        key_offset,
00555                         w_base_t::uint4_t         link_offset);
00556 
00557 protected:
00558     const K&            key_of(const T& t)  {
00559                         return * (K*) (((const char*)&t) + _key_offset);
00560                         }
00561 
00562     using w_list_t<T,LOCK>::_tail;
00563     using w_list_t<T,LOCK>::base_of;
00564 
00565 private:
00566     // disabled
00567     NORET            w_keyed_list_t(const     w_keyed_list_t<T,LOCK,K>&);
00568     w_base_t::uint4_t        _key_offset;
00569 
00570     // disabled
00571     w_list_t<T,LOCK>&            push(T* t);
00572     w_list_t<T,LOCK>&            append(T* t) ;
00573     T*                      chop();
00574     T*                      top();
00575     T*                      bottom();
00576 };
00577 
00578 #define    W_KEYED_ARG(class,key,link)    \
00579     W_LIST_ARG(class,key), W_LIST_ARG(class,link) 
00580 
00581 /**\brief List maintained in ascending order. 
00582  *
00583  * T is the type of the objects in the list.
00584  * K is the type of the key used for sorting.
00585  *   This type must have an operator <=.
00586  */
00587 template <class T, class LOCK, class K>
00588 class w_ascend_list_t : public w_keyed_list_t<T,LOCK, K>  {
00589     using w_keyed_list_t<T,LOCK, K>::_tail;
00590     using w_keyed_list_t<T,LOCK, K>::base_of;
00591 
00592 public:
00593     NORET            w_ascend_list_t(
00594         w_base_t::uint4_t         key_offset,
00595         w_base_t::uint4_t        link_offset,
00596         LOCK *lock)
00597         : w_keyed_list_t<T,LOCK, K>(key_offset, link_offset, lock)   { };
00598     NORET            ~w_ascend_list_t()    {};
00599 
00600     virtual T*          search(const K& k);
00601     virtual void        put_in_order(T* t);
00602 
00603 private:
00604     NORET               w_ascend_list_t(
00605                             const w_ascend_list_t<T,LOCK,K>&); // disabled
00606 };
00607 
00608 /**\brief List maintained in descending order. 
00609  *
00610  * T is the type of the objects in the list.
00611  * K is the type of the key used for sorting.
00612  *   This type must have an operator >=.
00613  */
00614 template <class T, class LOCK, class K>
00615 class w_descend_list_t : public w_keyed_list_t<T,LOCK, K> 
00616 {
00617     using w_keyed_list_t<T,LOCK, K>::_tail;
00618     using w_keyed_list_t<T,LOCK, K>::base_of;
00619 
00620 public:
00621     NORET            w_descend_list_t(
00622                         w_base_t::uint4_t         key_offset,
00623                         w_base_t::uint4_t        link_offset,
00624                         LOCK *l)
00625                         : w_keyed_list_t<T,LOCK, K>(
00626                                 key_offset, link_offset, l)   { };
00627     NORET            ~w_descend_list_t()    {};
00628 
00629     virtual T*        search(const K& k);
00630     virtual void      put_in_order(T* t);
00631 
00632 private:
00633     NORET            w_descend_list_t(
00634                             const w_descend_list_t<T,LOCK,K>&); // disabled
00635 };
00636 
00637 
00638 
00639 template <class T, class LOCK>
00640 ostream&
00641 operator<<(
00642     ostream&            o,
00643     const w_list_t<T,LOCK>&        l)
00644 {
00645     const w_link_t* p = l._tail.next();
00646 
00647     cout << "cnt = " << l.num_members();
00648 
00649     while (p != &l._tail)  {
00650     const T* t = l.base_of(p);
00651     if (! (o << endl << '\t' << *t))  break;
00652     p = p->next();
00653     }
00654     return o;
00655 }
00656 
00657 
00658 template <class T, class LOCK, class K>
00659 NORET
00660 w_keyed_list_t<T,LOCK, K>::w_keyed_list_t(
00661     w_base_t::uint4_t        key_offset,
00662     w_base_t::uint4_t        link_offset,
00663     LOCK*                    lock
00664     )
00665     : w_list_t<T,LOCK>(link_offset, lock), _key_offset(key_offset)    
00666 {
00667 #ifdef __GNUC__
00668 #else
00669     w_assert9(key_offset + sizeof(K) <= sizeof(T));
00670 #endif
00671 }
00672 
00673 template <class T, class LOCK, class K>
00674 NORET
00675 w_keyed_list_t<T,LOCK, K>::w_keyed_list_t(LOCK *l)
00676     : w_list_t<T,LOCK>(0,l), _key_offset(0)
00677 {
00678 }
00679 
00680 template <class T, class LOCK, class K>
00681 void
00682 w_keyed_list_t<T,LOCK, K>::set_offset(
00683     w_base_t::uint4_t        key_offset,
00684     w_base_t::uint4_t        link_offset) 
00685 {
00686     w_assert3(_key_offset == 0);
00687     w_list_t<T,LOCK>::set_offset(link_offset);
00688     _key_offset = key_offset;
00689 }
00690 
00691 template <class T, class LOCK, class K>
00692 T*
00693 w_keyed_list_t<T,LOCK, K>::search(const K& k)
00694 {
00695     w_link_t    *p;
00696     for (p = _tail.next();
00697      p != &_tail && (key_of(*base_of(p)) != k);
00698      p = p->next()) ;
00699     return (p && (p!=&_tail)) ? base_of(p) : 0;
00700 }
00701 
00702 template <class T, class LOCK, class K>
00703 T*
00704 w_ascend_list_t<T,LOCK, K>::search(const K& k)
00705 {
00706     w_link_t    *p;
00707     for (p = _tail.next();
00708      p != &_tail && (key_of(*base_of(p)) < k);
00709      p = p->next()) ;
00710 
00711     return p ? base_of(p) : 0;
00712 }
00713 
00714 template <class T, class LOCK, class K>
00715 void
00716 w_ascend_list_t<T,LOCK, K>::put_in_order(T* t)
00717 {
00718     w_link_t    *p;
00719     for (p = _tail.next();
00720      p != &_tail && (key_of(*base_of(p)) <= key_of(*t));
00721      p = p->next()) ;
00722 
00723     if (p)  {
00724     link_of(t)->attach(p->prev());
00725     } else {
00726         link_of(t)->attach(_tail.prev());
00727     }
00728 }
00729 
00730 template <class T, class LOCK, class K>
00731 T*
00732 w_descend_list_t<T,LOCK, K>::search(const K& k)
00733 {
00734     w_link_t    *p;
00735     for (p = _tail.next();
00736      p != &_tail && (key_of(*base_of(p)) > k);
00737      p = p->next()) ;
00738 
00739     return p ? base_of(p) : 0;
00740 }
00741 
00742 template <class T, class LOCK, class K>
00743 void
00744 w_descend_list_t<T,LOCK, K>::put_in_order(T* t)
00745 {
00746     w_link_t    *p;
00747     for (p = _tail.next();
00748      p != &_tail && (key_of(*base_of(p)) >= key_of(*t));
00749      p = p->next()) ;
00750 
00751     if (p)  {
00752         link_of(t)->attach(p->prev());
00753     } else {
00754         link_of(t)->attach(_tail.prev());
00755     }
00756 }
00757 /*<std-footer incl-file-exclusion='W_LIST_H'>  -- do not edit anything below this line -- */
00758 
00759 #endif          /*</std-footer>*/

Generated on Wed Jul 7 17:22:32 2010 for Shore Storage Manager by  doxygen 1.4.7