+/* === E T L =============================================================== */
+/*! \file _handle.h
+** $Id$
+** \brief Template Object Handle Implementation
+** \internal
+**
+** \legal
+** Copyright (c) 2002 Robert B. Quattlebaum Jr.
+**
+** This package is free software; you can redistribute it and/or
+** modify it under the terms of the GNU General Public License as
+** published by the Free Software Foundation; either version 2 of
+** the License, or (at your option) any later version.
+**
+** This package is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+** General Public License for more details.
+** \endlegal
+**
+** \note
+** This is an internal header file, included by other ETL headers.
+** You should not attempt to use it directly.
+*/
+/* ========================================================================= */
+
+/* === S T A R T =========================================================== */
+
+#ifndef __ETL__HANDLE_H
+#define __ETL__HANDLE_H
+
+/* === H E A D E R S ======================================================= */
+
+#include <cassert>
+
+/* === M A C R O S ========================================================= */
+
+/* === T Y P E D E F S ===================================================== */
+
+#define ETL_SELF_DELETING_SHARED_OBJECT
+
+/* === C L A S S E S & S T R U C T S ======================================= */
+
+#ifdef NDEBUG
+#define assert_cast static_cast
+#else
+#define assert_cast dynamic_cast
+#endif
+
+
+_ETL_BEGIN_NAMESPACE
+
+// Forward Declarations
+template <class T> class handle;
+template <class T> class loose_handle;
+template <class T> class rhandle;
+
+
+// ========================================================================
+/*! \class shared_object _handle.h ETL/handle
+** \brief Shared Object Base Class
+** \see handle, loose_handle
+** \writeme
+*/
+class shared_object
+{
+private:
+ mutable int refcount;
+
+protected:
+ shared_object():refcount(0) { }
+
+#ifdef ETL_SELF_DELETING_SHARED_OBJECT
+ virtual ~shared_object() { }
+#else
+ ~shared_object() { }
+#endif
+
+public:
+ void ref()const
+ { assert(refcount>=0); refcount++; }
+
+ //! Returns \c false if object needs to be deleted
+ bool unref()const
+ {
+ assert(refcount>0);
+
+ refcount--;
+
+ if(refcount==0) {
+#ifdef ETL_SELF_DELETING_SHARED_OBJECT
+ refcount=-666;
+ delete this;
+#endif
+ return false;
+ }
+
+ return true;
+ }
+
+ int count()const
+ { return refcount; }
+}; // END of class shared_object
+
+// ========================================================================
+/*! \class virtual_shared_object _handle.h ETL/handle
+** \brief Virtual Shared Object Base Class
+** \see handle, loose_handle
+** \writeme
+*/
+class virtual_shared_object
+{
+protected:
+ virtual_shared_object() { }
+public:
+ virtual ~virtual_shared_object()=0;
+ virtual void ref()const=0;
+ virtual bool unref()const=0;
+ virtual int count()const=0;
+ virtual virtual_shared_object *clone()=0;
+}; // END of class virtual_shared_object
+
+// ========================================================================
+/*! \class handle _handle.h ETL/handle
+** \brief Object Handle
+** \see shared_object, loose_handle
+** \writeme
+*/
+template <class T>
+class handle
+{
+public:
+
+ typedef T value_type;
+ typedef T& reference;
+ typedef const T& const_reference;
+ typedef T* pointer;
+ typedef const T* const_pointer;
+ typedef int count_type;
+ typedef int size_type;
+
+protected:
+ value_type *obj; //!< Pointer to object
+
+public:
+
+ //! Default constructor - empty handle
+ handle():obj(NULL) {}
+
+ //! Constructor that constructs from a pointer to new object
+ handle(pointer x):obj(x)
+ {
+ if(obj)
+ obj->ref();
+ }
+
+ //! Default copy constructor
+ handle(const handle<value_type> &x):obj(x.get())
+ {
+ if(obj)
+ obj->ref();
+ }
+
+ //! Handle is released on deletion
+ ~handle() { detach(); }
+
+ //! Template Assignment operator
+ /*! \note This class may not be necessary, and may be removed
+ ** at some point in the future.
+ */
+ /*
+ template <class U> handle<value_type> &
+ operator=(const handle<U> &x)
+ {
+ if(x.get()==obj)
+ return *this;
+
+ detach();
+
+ obj=static_cast<value_type*>(x.get());
+ if(obj)obj->ref();
+ return *this;
+ }
+ */
+
+ //! Assignment operator
+ handle<value_type> &
+ operator=(const handle<value_type> &x)
+ {
+ if(x.get()==obj)
+ return *this;
+
+ detach();
+
+ obj=x.get();
+ if(obj)obj->ref();
+ return *this;
+ }
+
+ //! Swaps the values of two handles without reference counts
+ handle<value_type> &
+ swap(handle<value_type> &x)
+ {
+ pointer ptr=x.obj;
+ x.obj=x.get();
+ obj=ptr;
+ return *this;
+ }
+
+ //! Handle detach procedure
+ /*! unref()'s the object and sets the internal object pointer to \c NULL */
+ void
+ detach()
+ {
+ pointer xobj(obj);
+ obj=0;
+#ifdef ETL_SELF_DELETING_SHARED_OBJECT
+ if(xobj)
+ xobj->unref();
+#else
+ if(xobj && !xobj->unref())
+ delete xobj;
+#endif
+ }
+
+ // This will be reintroduced with a new function
+ //void release() { detach(); }
+
+ void reset() { detach(); }
+
+ bool empty()const { return obj==0; }
+
+ //! Creates a new instance of a T object and puts it in the handle.
+ /*! Uses the default constructor */
+ void spawn() { operator=(handle(new T())); }
+
+ handle<value_type> clone()const { assert(obj); return static_cast<value_type*>(obj->clone()); }
+
+ //! Returns a constant handle to our object
+ handle<const value_type> constant()const { assert(obj); return *this; }
+
+ //! Returns number of instances
+ count_type
+ count()const
+ { return obj?obj->count():0; }
+
+ //! Returns true if there is only one instance of the object
+ bool
+ unique()const
+ { assert(obj); return count()==1; }
+
+ reference
+ operator*()const
+ { assert(obj); return *obj; }
+
+ pointer
+ operator->()const
+ { assert(obj); return obj; }
+
+ //! More explicit bool cast
+ operator bool()const
+ { return obj!=NULL; }
+
+ operator handle<const value_type>()const
+ { return handle<const value_type>(static_cast<const_pointer>(obj)); }
+
+
+ //! <tt> static_cast\<\> </tt> wrapper
+ template <class U> static
+ handle<T> cast_static(const handle<U> &x)
+ { return handle<T>(static_cast<T*>(x.get())); }
+
+ //! <tt> dynamic_cast\<\> </tt> wrapper
+ template <class U> static
+ handle<T> cast_dynamic(const handle<U> &x)
+ { return handle<T>(dynamic_cast<T*>(x.get())); }
+
+ //! <tt> const_cast\<\> </tt> wrapper
+ template <class U> static
+ handle<T> cast_const(const handle<U> &x)
+ { return handle<T>(const_cast<T*>(x.get())); }
+
+ //! <tt> reinterpret_cast\<\> </tt> wrapper
+ template <class U> static
+ handle<T> cast_reinterpret(const handle<U> &x)
+ { return handle<T>(reinterpret_cast<T*>(x.get())); }
+
+ template<class U> static handle<T> cast_static(const loose_handle<U> &x);
+ template<class U> static handle<T> cast_dynamic(const loose_handle<U> &x);
+ template<class U> static handle<T> cast_const(const loose_handle<U> &x);
+ template<class U> static handle<T> cast_reinterpret(const loose_handle<U> &x);
+
+ template<class U> static handle<T> cast_static(const rhandle<U> &x);
+ template<class U> static handle<T> cast_dynamic(const rhandle<U> &x);
+ template<class U> static handle<T> cast_const(const rhandle<U> &x);
+ template<class U> static handle<T> cast_reinterpret(const rhandle<U> &x);
+
+ template<class U> static handle<T> cast_static(U* x);
+ template<class U> static handle<T> cast_dynamic(U* x);
+ template<class U> static handle<T> cast_const(U* x);
+ template<class U> static handle<T> cast_reinterpret(U* x);
+
+ //! Returns pointer to the object that is being wrapped
+ pointer get()const { return obj; }
+
+ bool
+ operator!()const
+ { return !obj; }
+
+ //! static_cast<> overload -- Useful for implicit casts
+ template <class U>
+ operator handle<U>()const
+ { return handle<U>(static_cast<U*>(obj)); }
+}; // END of template class handle
+
+// ========================================================================
+/*! \class rshared_object _handle.h ETL/handle
+** \brief Replaceable Shared Object Base Class
+** \see rhandle
+** \writeme
+*/
+class rshared_object : public shared_object
+{
+private:
+ mutable int rrefcount;
+
+public:
+ void *front_;
+ void *back_;
+
+protected:
+ rshared_object():rrefcount(0),front_(0),back_(0) { }
+
+public:
+ void rref()const
+ { rrefcount++; }
+
+ void runref()const
+ {
+ assert(rrefcount>0);
+ rrefcount--;
+ }
+
+ int rcount()const
+ { return rrefcount; }
+}; // END of class rshared_object
+
+// ========================================================================
+/*! \class rhandle _handle.h ETL/handle
+** \brief Replaceable Object Handle
+** \see rshared_object, handle, loose_handle
+** \writeme
+*/
+template <class T>
+class rhandle : public handle<T>
+{
+ friend class rshared_object;
+public:
+
+ typedef T value_type;
+ typedef T& reference;
+ typedef const T& const_reference;
+ typedef T* pointer;
+ typedef const T* const_pointer;
+ typedef int count_type;
+ typedef int size_type;
+
+
+ using handle<value_type>::count;
+ using handle<value_type>::unique;
+ using handle<value_type>::operator bool;
+ using handle<value_type>::get;
+ using handle<value_type>::operator *;
+ using handle<value_type>::operator ->;
+
+ /*
+ operator const handle<value_type>&()const
+ { return *this; }
+ */
+
+private:
+ using handle<value_type>::obj;
+
+ rhandle<value_type> *prev_;
+ rhandle<value_type> *next_;
+
+ void add_to_rlist()
+ {
+// value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 form barfing
+
+ assert(obj);
+ obj->rref();
+
+ // If this is the first reversible handle
+ if(!obj->front_)
+ {
+ obj->front_=obj->back_=this;
+ prev_=next_=0;
+ return;
+ }
+
+ prev_=reinterpret_cast<rhandle<value_type>*>(obj->back_);
+ next_=0;
+ prev_->next_=this;
+ obj->back_=this;
+ }
+
+ void del_from_rlist()
+ {
+// value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 form barfing
+ assert(obj);
+ obj->runref();
+
+ // If this is the last reversible handle
+ if(obj->front_==obj->back_)
+ {
+ obj->front_=obj->back_=0;
+ prev_=next_=0;
+ return;
+ }
+
+ if(!prev_)
+ obj->front_=(void*)next_;
+ else
+ prev_->next_=next_;
+
+ if(!next_)
+ obj->back_=(void*)prev_;
+ else
+ next_->prev_=prev_;
+ }
+
+public:
+
+ //! Default constructor - empty handle
+ rhandle() {}
+
+ //! Constructor that constructs from a pointer to new object
+ rhandle(pointer x):handle<T>(x)
+ {
+// value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 form barfing
+ if(obj)add_to_rlist();
+ }
+
+ rhandle(const handle<value_type> &x):handle<T>(x)
+ {
+// value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 form barfing
+ if(obj)add_to_rlist();
+ }
+
+ //! Default copy constructor
+ rhandle(const rhandle<value_type> &x):handle<T>(x)
+ {
+// value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 form barfing
+ if(obj)add_to_rlist();
+ }
+
+ //! Handle is released on deletion
+ ~rhandle() { detach(); }
+
+ //! Template Assignment operator
+ /*! \note This class may not be necessary, and may be removed
+ ** at some point in the future.
+ */
+ /*
+ template <class U> const handle<value_type> &
+ operator=(const handle<U> &x)
+ {
+ if(x.get()==obj)
+ return *this;
+
+ detach();
+
+ obj=static_cast<value_type*>(x.get());
+ if(obj)
+ {
+ obj->ref();
+ add_to_rlist();
+ }
+ return *this;
+ }
+ */
+
+ //! Assignment operator
+ rhandle<value_type> &
+ operator=(const rhandle<value_type> &x)
+ {
+// value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 form barfing
+ if(x.get()==obj)
+ return *this;
+
+ detach();
+
+ obj=x.get();
+ if(obj)
+ {
+ obj->ref();
+ add_to_rlist();
+ }
+ return *this;
+ }
+
+ rhandle<value_type>&
+ operator=(const handle<value_type> &x)
+ {
+// value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 form barfing
+ if(x.get()==obj)
+ return *this;
+
+ detach();
+
+ obj=x.get();
+ if(obj)
+ {
+ obj->ref();
+ add_to_rlist();
+ }
+ return *this;
+ }
+
+ rhandle<value_type>&
+ operator=(value_type* x)
+ {
+// value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 form barfing
+ if(x==obj)
+ return *this;
+
+ detach();
+
+ obj=x;
+ if(obj)
+ {
+ obj->ref();
+ add_to_rlist();
+ }
+ return *this;
+ }
+
+ //! Handle release procedure
+ /*! unref()'s the object and sets the internal object pointer to \c NULL */
+ void
+ detach()
+ {
+// value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 form barfing
+ if(obj)del_from_rlist();
+ handle<value_type>::detach();
+ obj=0;
+ }
+
+ // This will be reintroduced with a new function
+ //void release() { detach(); }
+
+ void reset() { detach(); }
+
+ //! Creates a new instance of a T object and puts it in the handle.
+ /*! Uses the default constructor */
+ void spawn() { operator=(handle<value_type>(new T())); }
+
+ //! Returns number of reversible instances
+ count_type
+ rcount()const
+ {
+// value_type*const& obj(handle<T>::obj); // Required to keep gcc 3.4.2 form barfing
+ return obj?obj->rcount():0;
+ }
+
+ //! Returns true if there is only one instance of the object
+ bool
+ runique()const
+ {
+// value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 form barfing
+ assert(obj); return obj->front_==obj->back_;
+ }
+
+ //! \writeme
+ int replace(const handle<value_type> &x)
+ {
+// value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 form barfing
+ assert(obj);
+ assert(x.get()!=obj);
+
+ if(x.get()==obj)
+ return 0;
+
+ rhandle<value_type> *iter;
+ rhandle<value_type> *next;
+
+ iter=reinterpret_cast<rhandle<value_type>*>(obj->front_);
+
+ assert(iter);
+
+ next=iter->next_;
+
+ int i=0;
+ #ifndef NDEBUG
+ pointer obj_=obj;
+ #endif
+
+ for(;iter;iter=next,next=iter?iter->next_:0,i++)
+ {
+ assert(iter->get()==obj_);
+ (*iter)=x;
+ }
+
+ assert(obj==x.get());
+
+ return i;
+ }
+
+ //! Swaps the values of two handles without reference counts
+ /*! \warning not yet implemented. \writeme */
+ handle<value_type> &
+ swap(handle<value_type> &x);
+ /*
+ {
+ assert(0);
+ pointer ptr=x.obj;
+ x.obj=x.get();
+ obj=ptr;
+ return *this;
+ }
+ */
+}; // END of template class rhandle
+
+
+
+
+
+
+
+// ========================================================================
+/*! \class loose_handle _handle.h ETL/handle
+** \brief Loose Object Handle
+** \see shared_object, handle
+** \writeme
+*/
+template <class T>
+class loose_handle
+{
+public:
+
+ typedef T value_type;
+ typedef T& reference;
+ typedef const T& const_reference;
+ typedef T* pointer;
+ typedef const T* const_pointer;
+ typedef int count_type;
+ typedef int size_type;
+
+protected:
+ value_type *obj; //!< Pointer to object
+
+public:
+
+ //! Default constructor - empty handle
+ loose_handle():obj(0) {}
+
+ //! Constructor that constructs from a pointer to new object
+ loose_handle(pointer x):obj(x) { }
+
+ //! Default copy constructor
+ loose_handle(const loose_handle<value_type> &x):obj(x.get()) { }
+
+ loose_handle(const handle<value_type> &x):obj(x.get()) { }
+
+ template <class U> const loose_handle<value_type> &
+ operator=(const handle<U> &x)
+ {
+ if(x.get()==obj)
+ return *this;
+
+ obj=static_cast<value_type*>(x.get());
+ return *this;
+ }
+
+ template <class U> const loose_handle<value_type> &
+ operator=(const loose_handle<U> &x)
+ {
+ if(x.get()==obj)
+ return *this;
+
+ obj=static_cast<value_type*>(x.get());
+ return *this;
+ }
+
+ //! Assignment operator
+ const loose_handle<value_type> &
+ operator=(const loose_handle<value_type> &x)
+ {
+ if(x.get()==obj)
+ return *this;
+
+ obj=x.get();
+ return *this;
+ }
+
+ //! Swaps the values of two handles without reference counts
+ loose_handle<value_type> &
+ swap(loose_handle<value_type> &x)
+ {
+ pointer ptr=x.obj;
+ x.obj=x.get();
+ obj=ptr;
+ return *this;
+ }
+
+ //! Handle release procedure
+ void detach() { obj=0; }
+
+ // This will be reintroduced with a new function
+ //void release() { detach(); }
+
+ void reset() { detach(); }
+
+ bool empty()const { return obj==0; }
+
+ handle<value_type> clone()const { assert(obj); return obj->clone(); }
+
+ //! Returns a constant handle to our object
+ loose_handle<const value_type> constant()const { return *this; }
+
+ //! Returns number of instances
+ count_type
+ count()const
+ { return obj?obj->count():0; }
+
+ reference
+ operator*()const
+ { assert(obj); return *obj; }
+
+ pointer
+ operator->()const
+ { assert(obj); return obj; }
+
+ //! static_cast<> overload
+ //template <class U>
+ //operator loose_handle<U>()const
+ //{ return loose_handle<U>(static_cast<U*>(obj)); }
+
+ //! static_cast<> overload (for consts)
+ operator loose_handle<const value_type>()const
+ { return loose_handle<const value_type>(static_cast<const_pointer>(obj)); }
+
+ operator handle<value_type>()const
+ { return handle<value_type>(obj); }
+
+ operator rhandle<value_type>()const
+ { return rhandle<value_type>(obj); }
+
+ //! Returns pointer to the object that is being wrapped
+ pointer get()const { return obj; }
+
+ //! More explicit bool cast
+ operator bool()const
+ { return obj!=0; }
+
+ bool
+ operator!()const
+ { return !obj; }
+
+ void ref() { if(obj)obj->ref(); }
+
+ bool unref() { if(obj && !obj->unref()){ obj=0; return false; } return true; }
+}; // END of template class loose_handle
+
+
+
+
+template<class T> template<class U> handle<T>
+handle<T>::cast_static(const loose_handle<U> &x)
+ { return handle<T>(static_cast<T*>(x.get())); }
+
+template <class T> template <class U> handle<T>
+handle<T>::cast_dynamic(const loose_handle<U> &x)
+ { return handle<T>(dynamic_cast<T*>(x.get())); }
+
+template <class T> template <class U> handle<T>
+handle<T>::cast_const(const loose_handle<U> &x)
+ { return handle<T>(const_cast<T*>(x.get())); }
+
+template <class T> template <class U> handle<T>
+handle<T>::cast_reinterpret(const loose_handle<U> &x)
+ { return handle<T>(reinterpret_cast<T*>(x.get())); }
+
+
+
+template <class T> template <class U> handle<T>
+handle<T>::cast_static(const rhandle<U> &x)
+ { return handle<T>(static_cast<T*>(x.get())); }
+
+template <class T> template <class U> handle<T>
+handle<T>::cast_dynamic(const rhandle<U> &x)
+ { return handle<T>(dynamic_cast<T*>(x.get())); }
+
+template <class T> template <class U> handle<T>
+handle<T>::cast_const(const rhandle<U> &x)
+ { return handle<T>(const_cast<T*>(x.get())); }
+
+template <class T> template <class U> handle<T>
+handle<T>::cast_reinterpret(const rhandle<U> &x)
+ { return handle<T>(reinterpret_cast<T*>(x.get())); }
+
+
+
+template <class T> template <class U> handle<T>
+handle<T>::cast_static(U* x)
+ { return handle<T>(static_cast<T*>(x)); }
+
+template <class T> template <class U> handle<T>
+handle<T>::cast_dynamic(U* x)
+ { return handle<T>(dynamic_cast<T*>(x)); }
+
+template <class T> template <class U> handle<T>
+handle<T>::cast_const(U* x)
+ { return handle<T>(const_cast<T*>(x)); }
+
+template <class T> template <class U> handle<T>
+handle<T>::cast_reinterpret(U* x)
+ { return handle<T>(reinterpret_cast<T*>(x)); }
+
+
+
+
+
+template <class T,class U> bool
+operator==(const handle<T> &lhs,const handle<U> &rhs)
+ { return (lhs.get()==rhs.get()); }
+template <class T,class U> bool
+operator==(const loose_handle<T> &lhs,const loose_handle<U> &rhs)
+ { return (lhs.get()==rhs.get()); }
+template <class T,class U> bool
+operator==(const handle<T> &lhs,const loose_handle<U> &rhs)
+ { return (lhs.get()==rhs.get()); }
+template <class T,class U> bool
+operator==(const loose_handle<T> &lhs,const handle<U> &rhs)
+ { return (lhs.get()==rhs.get()); }
+template <class T> bool
+operator==(const handle<T> &lhs,const T *rhs)
+ { return (lhs.get()==rhs); }
+template <class T> bool
+operator==(const loose_handle<T> &lhs,const T *rhs)
+ { return (lhs.get()==rhs); }
+template <class T> bool
+operator==(const T *lhs,const handle<T> &rhs)
+ { return (lhs==rhs.get()); }
+template <class T> bool
+operator==(const T *lhs,const loose_handle<T> &rhs)
+ { return (lhs==rhs.get()); }
+
+
+template <class T,class U> bool
+operator!=(const handle<T> &lhs,const handle<U> &rhs)
+ { return (lhs.get()!=rhs.get()); }
+template <class T,class U> bool
+operator!=(const loose_handle<T> &lhs,const loose_handle<U> &rhs)
+ { return (lhs.get()!=rhs.get()); }
+template <class T,class U> bool
+operator!=(const handle<T> &lhs,const loose_handle<U> &rhs)
+ { return (lhs.get()!=rhs.get()); }
+template <class T,class U> bool
+operator!=(const loose_handle<T> &lhs,const handle<U> &rhs)
+ { return (lhs.get()!=rhs.get()); }
+template <class T> bool
+operator!=(const handle<T> &lhs,const T *rhs)
+ { return (lhs.get()!=rhs); }
+template <class T> bool
+operator!=(const loose_handle<T> &lhs,const T *rhs)
+ { return (lhs.get()!=rhs); }
+template <class T> bool
+operator!=(const T *lhs,const handle<T> &rhs)
+ { return (lhs!=rhs.get()); }
+template <class T> bool
+operator!=(const T *lhs,const loose_handle<T> &rhs)
+ { return (lhs!=rhs.get()); }
+
+
+template <class T,class U> bool
+operator<(const handle<T> &lhs,const handle<U> &rhs)
+ { return (lhs.get()<rhs.get()); }
+template <class T,class U> bool
+operator<(const loose_handle<T> &lhs,const loose_handle<U> &rhs)
+ { return (lhs.get()<rhs.get()); }
+template <class T,class U> bool
+operator<(const handle<T> &lhs,const loose_handle<U> &rhs)
+ { return (lhs.get()<rhs.get()); }
+template <class T,class U> bool
+operator<(const loose_handle<T> &lhs,const handle<U> &rhs)
+ { return (lhs.get()<rhs.get()); }
+template <class T> bool
+operator<(const handle<T> &lhs,const T *rhs)
+ { return (lhs.get()<rhs); }
+template <class T> bool
+operator<(const loose_handle<T> &lhs,const T *rhs)
+ { return (lhs.get()<rhs); }
+template <class T> bool
+operator<(const T *lhs,const handle<T> &rhs)
+ { return (lhs<rhs.get()); }
+template <class T> bool
+operator<(const T *lhs,const loose_handle<T> &rhs)
+ { return (lhs<rhs.get()); }
+
+_ETL_END_NAMESPACE
+
+/* === E N D =============================================================== */
+
+#endif