Use etl::mutexes to lock access to reference counts.
[synfig.git] / ETL / trunk / ETL / _handle.h
1 /* === E T L =============================================================== */
2 /*!     \file _handle.h
3 **      $Id$
4 **      \brief Template Object Handle Implementation
5 **      \internal
6 **
7 **      \legal
8 **      Copyright (c) 2002 Robert B. Quattlebaum Jr.
9 **      Copyright (c) 2007 Chris Moore
10 **
11 **      This package is free software; you can redistribute it and/or
12 **      modify it under the terms of the GNU General Public License as
13 **      published by the Free Software Foundation; either version 2 of
14 **      the License, or (at your option) any later version.
15 **
16 **      This package is distributed in the hope that it will be useful,
17 **      but WITHOUT ANY WARRANTY; without even the implied warranty of
18 **      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19 **      General Public License for more details.
20 **      \endlegal
21 **
22 **      \note
23 **              This is an internal header file, included by other ETL headers.
24 **              You should not attempt to use it directly.
25 */
26 /* ========================================================================= */
27
28 /* === S T A R T =========================================================== */
29
30 #ifndef __ETL__HANDLE_H
31 #define __ETL__HANDLE_H
32
33 /* === H E A D E R S ======================================================= */
34
35 // include the next line in an attempt to increase stability
36 #define ETL_LOCK_REFCOUNTS
37
38 #include <cassert>
39
40 #ifdef ETL_LOCK_REFCOUNTS
41 #  include "_mutex_simple.h"
42 #endif
43
44 /* === M A C R O S ========================================================= */
45
46 /* === T Y P E D E F S ===================================================== */
47
48 #define ETL_SELF_DELETING_SHARED_OBJECT
49
50 /* === C L A S S E S & S T R U C T S ======================================= */
51
52 #ifdef NDEBUG
53 #define assert_cast             static_cast
54 #else
55 #define assert_cast             dynamic_cast
56 #endif
57
58
59 _ETL_BEGIN_NAMESPACE
60
61 // Forward Declarations
62 template <class T> class handle;
63 template <class T> class loose_handle;
64 template <class T> class rhandle;
65
66
67 // ========================================================================
68 /*!     \class  shared_object _handle.h ETL/handle
69 **      \brief  Shared Object Base Class
70 **      \see handle, loose_handle
71 **      \writeme
72 */
73 class shared_object
74 {
75 private:
76         mutable int refcount;
77 #ifdef ETL_LOCK_REFCOUNTS
78         mutable etl::mutex mtx;
79 #endif
80
81 protected:
82         shared_object():refcount(0) { }
83
84 #ifdef ETL_SELF_DELETING_SHARED_OBJECT
85         virtual ~shared_object() { }
86 #else
87         ~shared_object() { }
88 #endif
89
90 public:
91         void ref()const
92         {
93 #ifdef ETL_LOCK_REFCOUNTS
94                 etl::mutex::lock lock(mtx);
95 #endif
96                 assert(refcount>=0);
97                 refcount++;
98         }
99
100         //! Returns \c false if object needs to be deleted
101         bool unref()const
102         {
103                 bool ret = true;
104                 {
105 #ifdef ETL_LOCK_REFCOUNTS
106                         etl::mutex::lock lock(mtx);
107 #endif
108                         assert(refcount>0);
109
110                         refcount--;
111
112                         if(refcount==0) {
113                                 ret = false;
114 #ifdef ETL_SELF_DELETING_SHARED_OBJECT
115                                 refcount=-666;
116 #endif
117                         }
118                 }
119
120 #ifdef ETL_SELF_DELETING_SHARED_OBJECT
121                 if (!ret)
122                         delete this;
123 #endif
124                 return ret;
125         }
126
127         int count()const { return refcount; }
128
129 }; // END of class shared_object
130
131 // ========================================================================
132 /*!     \class  virtual_shared_object _handle.h ETL/handle
133 **      \brief  Virtual Shared Object Base Class
134 **      \see handle, loose_handle
135 **      \writeme
136 */
137 class virtual_shared_object
138 {
139 protected:
140         virtual_shared_object() { }
141 public:
142         virtual ~virtual_shared_object()=0;
143         virtual void ref()const=0;
144         virtual bool unref()const=0;
145         virtual int count()const=0;
146         virtual virtual_shared_object *clone()=0;
147 }; // END of class virtual_shared_object
148
149 // ========================================================================
150 /*!     \class  handle _handle.h        ETL/handle
151 **      \brief  Object Handle
152 **      \see shared_object, loose_handle
153 **      \writeme
154 */
155 template <class T>
156 class handle
157 {
158 public:
159
160         typedef T value_type;
161         typedef T& reference;
162         typedef const T& const_reference;
163         typedef T* pointer;
164         typedef const T* const_pointer;
165         typedef int count_type;
166         typedef int size_type;
167
168 protected:
169 #ifdef _DEBUG
170 public:
171 #endif
172         value_type *obj;                //!< Pointer to object
173
174 public:
175
176         //! Default constructor - empty handle
177         handle():obj(NULL) {}
178
179         //! Constructor that constructs from a pointer to new object
180         handle(pointer x):obj(x)
181         {
182                 if(obj)
183                         obj->ref();
184         }
185
186         //! Default copy constructor
187         handle(const handle<value_type> &x):obj(x.get())
188         {
189                 if(obj)
190                         obj->ref();
191         }
192
193         //! Handle is released on deletion
194         ~handle() { detach(); }
195
196         //! Template Assignment operator
197         /*! \note This class may not be necessary, and may be removed
198         **              at some point in the future.
199         */
200         /*
201         template <class U> handle<value_type> &
202         operator=(const handle<U> &x)
203         {
204                 if(x.get()==obj)
205                         return *this;
206
207                 detach();
208
209                 obj=static_cast<value_type*>(x.get());
210                 if(obj)obj->ref();
211                 return *this;
212         }
213         */
214
215         //! Assignment operator
216         handle<value_type> &
217         operator=(const handle<value_type> &x)
218         {
219                 if(x.get()==obj)
220                         return *this;
221
222                 detach();
223
224                 obj=x.get();
225                 if(obj)obj->ref();
226                 return *this;
227         }
228
229         //! Swaps the values of two handles without reference counts
230         handle<value_type> &
231         swap(handle<value_type> &x)
232         {
233                 pointer ptr=x.obj;
234                 x.obj=x.get();
235                 obj=ptr;
236                 return *this;
237         }
238
239         //! Handle detach procedure
240         /*! unref()'s the object and sets the internal object pointer to \c NULL */
241         void
242         detach()
243         {
244                 pointer xobj(obj);
245                 obj=0;
246 #ifdef ETL_SELF_DELETING_SHARED_OBJECT
247                 if(xobj)
248                         xobj->unref();
249 #else
250                 if(xobj && !xobj->unref())
251                         delete xobj;
252 #endif
253         }
254
255         // This will be reintroduced with a new function
256         //void release() { detach(); }
257
258         void reset() { detach(); }
259
260         bool empty()const { return obj==0; }
261
262         //! Creates a new instance of a T object and puts it in the handle.
263         /*! Uses the default constructor */
264         void spawn() { operator=(handle(new T())); }
265
266         handle<value_type> clone()const { assert(obj); return static_cast<value_type*>(obj->clone()); }
267
268         //! Returns a constant handle to our object
269         handle<const value_type> constant()const { assert(obj); return *this; }
270
271         //! Returns number of instances
272         count_type
273         count()const
274                 { return obj?obj->count():0; }
275
276         //! Returns true if there is only one instance of the object
277         bool
278         unique()const
279                 { assert(obj); return count()==1; }
280
281         reference
282         operator*()const
283                 { assert(obj); return *obj; }
284
285         pointer
286         operator->()const
287                 { assert(obj); return obj; }
288
289         //! More explicit bool cast
290         operator bool()const
291                 { return obj!=NULL; }
292
293         operator handle<const value_type>()const
294         { return handle<const value_type>(static_cast<const_pointer>(obj)); }
295
296         //! <tt> static_cast\<\> </tt> wrapper
297         template <class U> static handle<T> cast_static         (const handle<U> &x) { return handle<T>(static_cast             <T*>(x.get())); }
298         //! <tt> dynamic_cast\<\> </tt> wrapper
299         template <class U> static handle<T> cast_dynamic        (const handle<U> &x) { return handle<T>(dynamic_cast    <T*>(x.get())); }
300         //! <tt> const_cast\<\> </tt> wrapper
301         template <class U> static handle<T> cast_const          (const handle<U> &x) { return handle<T>(const_cast              <T*>(x.get())); }
302         //! <tt> reinterpret_cast\<\> </tt> wrapper
303         template <class U> static handle<T> cast_reinterpret(const handle<U> &x) { return handle<T>(reinterpret_cast<T*>(x.get())); }
304
305         template <class U> static handle<T> cast_static         (const loose_handle<U> &x);
306         template <class U> static handle<T> cast_dynamic        (const loose_handle<U> &x);
307         template <class U> static handle<T> cast_const          (const loose_handle<U> &x);
308         template <class U> static handle<T> cast_reinterpret(const loose_handle<U> &x);
309
310         template <class U> static handle<T> cast_static         (const rhandle<U> &x);
311         template <class U> static handle<T> cast_dynamic        (const rhandle<U> &x);
312         template <class U> static handle<T> cast_const          (const rhandle<U> &x);
313         template <class U> static handle<T> cast_reinterpret(const rhandle<U> &x);
314
315         template <class U> static handle<T> cast_static         (U* x);
316         template <class U> static handle<T> cast_dynamic        (U* x);
317         template <class U> static handle<T> cast_const          (U* x);
318         template <class U> static handle<T> cast_reinterpret(U* x);
319
320         //! Returns pointer to the object that is being wrapped
321         pointer get()const { return obj; }
322
323         bool
324         operator!()const
325                 { return !obj; }
326
327         //! static_cast<> overload -- Useful for implicit casts
328         template <class U>
329         operator handle<U>()const
330         { return handle<U>(static_cast<U*>(obj)); }
331 }; // END of template class handle
332
333 // ========================================================================
334 /*!     \class  rshared_object _handle.h        ETL/handle
335 **      \brief  Replaceable Shared Object Base Class
336 **      \see rhandle
337 **      \writeme
338 */
339 class rshared_object : public shared_object
340 {
341 private:
342         mutable int rrefcount;
343
344 public:
345         void *front_;
346         void *back_;
347
348 protected:
349         rshared_object():rrefcount(0),front_(0),back_(0) { }
350
351 public:
352         void rref()const
353                 { rrefcount++; }
354
355         void runref()const
356         {
357                 assert(rrefcount>0);
358                 rrefcount--;
359         }
360
361         int rcount()const
362                 { return rrefcount; }
363 }; // END of class rshared_object
364
365 // ========================================================================
366 /*!     \class  rhandle _handle.h       ETL/handle
367 **      \brief  Replaceable Object Handle
368 **      \see rshared_object, handle, loose_handle
369 **      \writeme
370 */
371 template <class T>
372 class rhandle : public handle<T>
373 {
374         friend class rshared_object;
375 public:
376
377         typedef T value_type;
378         typedef T& reference;
379         typedef const T& const_reference;
380         typedef T* pointer;
381         typedef const T* const_pointer;
382         typedef int count_type;
383         typedef int size_type;
384
385
386         using handle<value_type>::count;
387         using handle<value_type>::unique;
388         using handle<value_type>::operator bool;
389         using handle<value_type>::get;
390         using handle<value_type>::operator*;
391         using handle<value_type>::operator->;
392
393         /*
394         operator const handle<value_type>&()const
395         { return *this; }
396         */
397
398 private:
399         using handle<value_type>::obj;
400
401         rhandle<value_type> *prev_;
402         rhandle<value_type> *next_;
403
404         void add_to_rlist()
405         {
406 //              value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 from barfing
407
408                 assert(obj);
409                 obj->rref();
410
411                 // If this is the first reversible handle
412                 if(!obj->front_)
413                 {
414                         obj->front_=obj->back_=this;
415                         prev_=next_=0;
416                         return;
417                 }
418
419                 prev_=reinterpret_cast<rhandle<value_type>*>(obj->back_);
420                 next_=0;
421                 prev_->next_=this;
422                 obj->back_=this;
423         }
424
425         void del_from_rlist()
426         {
427 //              value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 from barfing
428                 assert(obj);
429                 obj->runref();
430
431                 // If this is the last reversible handle
432                 if(obj->front_==obj->back_)
433                 {
434                         obj->front_=obj->back_=0;
435                         prev_=next_=0;
436                         return;
437                 }
438
439                 if(!prev_)
440                         obj->front_=(void*)next_;
441                 else
442                         prev_->next_=next_;
443
444                 if(!next_)
445                         obj->back_=(void*)prev_;
446                 else
447                         next_->prev_=prev_;
448         }
449
450 public:
451
452         //! Default constructor - empty handle
453         rhandle() {}
454
455         //! Constructor that constructs from a pointer to new object
456         rhandle(pointer x):handle<T>(x)
457         {
458 //              value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 from barfing
459                 if(obj)add_to_rlist();
460         }
461
462         rhandle(const handle<value_type> &x):handle<T>(x)
463         {
464 //              value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 from barfing
465                 if(obj)add_to_rlist();
466         }
467
468         //! Default copy constructor
469         rhandle(const rhandle<value_type> &x):handle<T>(x)
470         {
471 //              value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 from barfing
472                 if(obj)add_to_rlist();
473         }
474
475         //! Handle is released on deletion
476         ~rhandle() { detach(); }
477
478         //! Template Assignment operator
479         /*! \note This class may not be necessary, and may be removed
480         **              at some point in the future.
481         */
482         /*
483         template <class U> const handle<value_type> &
484         operator=(const handle<U> &x)
485         {
486                 if(x.get()==obj)
487                         return *this;
488
489                 detach();
490
491                 obj=static_cast<value_type*>(x.get());
492                 if(obj)
493                 {
494                         obj->ref();
495                         add_to_rlist();
496                 }
497                 return *this;
498         }
499         */
500
501         //! Assignment operator
502         rhandle<value_type> &
503         operator=(const rhandle<value_type> &x)
504         {
505 //              value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 from barfing
506                 if(x.get()==obj)
507                         return *this;
508
509                 detach();
510
511                 obj=x.get();
512                 if(obj)
513                 {
514                         obj->ref();
515                         add_to_rlist();
516                 }
517                 return *this;
518         }
519
520         rhandle<value_type>&
521         operator=(const handle<value_type> &x)
522         {
523 //              value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 from barfing
524                 if(x.get()==obj)
525                         return *this;
526
527                 detach();
528
529                 obj=x.get();
530                 if(obj)
531                 {
532                         obj->ref();
533                         add_to_rlist();
534                 }
535                 return *this;
536         }
537
538         rhandle<value_type>&
539         operator=(value_type* x)
540         {
541 //              value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 from barfing
542                 if(x==obj)
543                         return *this;
544
545                 detach();
546
547                 obj=x;
548                 if(obj)
549                 {
550                         obj->ref();
551                         add_to_rlist();
552                 }
553                 return *this;
554         }
555
556         //! Handle release procedure
557         /*! unref()'s the object and sets the internal object pointer to \c NULL */
558         void
559         detach()
560         {
561 //              value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 from barfing
562                 if(obj)del_from_rlist();
563                 handle<value_type>::detach();
564                 obj=0;
565         }
566
567         // This will be reintroduced with a new function
568         //void release() { detach(); }
569
570         void reset() { detach(); }
571
572         //! Creates a new instance of a T object and puts it in the handle.
573         /*! Uses the default constructor */
574         void spawn() { operator=(handle<value_type>(new T())); }
575
576         //! Returns number of reversible instances
577         count_type
578         rcount()const
579         {
580 //              value_type*const& obj(handle<T>::obj); // Required to keep gcc 3.4.2 from barfing
581                 return obj?obj->rcount():0;
582         }
583
584         //! Returns true if there is only one instance of the object
585         bool
586         runique()const
587         {
588 //              value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 from barfing
589                 assert(obj); return obj->front_==obj->back_;
590         }
591
592         //! \writeme
593         int replace(const handle<value_type> &x)
594         {
595 //              value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 from barfing
596                 assert(obj);
597                 assert(x.get()!=obj);
598
599                 if(x.get()==obj)
600                         return 0;
601
602                 rhandle<value_type> *iter;
603                 rhandle<value_type> *next;
604
605                 iter=reinterpret_cast<rhandle<value_type>*>(obj->front_);
606
607                 assert(iter);
608
609                 next=iter->next_;
610
611                 int i=0;
612                 #ifndef NDEBUG
613                 pointer obj_=obj;
614                 #endif
615
616                 for(;iter;iter=next,next=iter?iter->next_:0,i++)
617                 {
618                         assert(iter->get()==obj_);
619                         (*iter)=x;
620                 }
621
622                 assert(obj==x.get());
623
624                 return i;
625         }
626
627         //! Swaps the values of two handles without reference counts
628         /*!     \warning not yet implemented. \writeme */
629         handle<value_type> &
630         swap(handle<value_type> &x);
631         /*
632         {
633                 assert(0);
634                 pointer ptr=x.obj;
635                 x.obj=x.get();
636                 obj=ptr;
637                 return *this;
638         }
639         */
640 }; // END of template class rhandle
641
642
643 // ========================================================================
644 /*!     \class  loose_handle _handle.h  ETL/handle
645 **      \brief  Loose Object Handle
646 **      \see shared_object, handle
647 **      \writeme
648 */
649 template <class T>
650 class loose_handle
651 {
652 public:
653
654         typedef T value_type;
655         typedef T& reference;
656         typedef const T& const_reference;
657         typedef T* pointer;
658         typedef const T* const_pointer;
659         typedef int count_type;
660         typedef int size_type;
661
662 protected:
663 #ifdef _DEBUG
664 public:
665 #endif
666         value_type *obj;                //!< Pointer to object
667
668 public:
669
670         //! Default constructor - empty handle
671         loose_handle():obj(0) {}
672
673         //! Constructor that constructs from a pointer to new object
674         loose_handle(pointer x):obj(x) { }
675
676         //! Default copy constructor
677         loose_handle(const loose_handle<value_type> &x):obj(x.get()) { }
678
679         loose_handle(const handle<value_type> &x):obj(x.get()) { }
680
681         template <class U> const loose_handle<value_type> &
682         operator=(const handle<U> &x)
683         {
684                 if(x.get()==obj)
685                         return *this;
686
687                 obj=static_cast<value_type*>(x.get());
688                 return *this;
689         }
690
691         template <class U> const loose_handle<value_type> &
692         operator=(const loose_handle<U> &x)
693         {
694                 if(x.get()==obj)
695                         return *this;
696
697                 obj=static_cast<value_type*>(x.get());
698                 return *this;
699         }
700
701         //! Assignment operator
702         const loose_handle<value_type> &
703         operator=(const loose_handle<value_type> &x)
704         {
705                 if(x.get()==obj)
706                         return *this;
707
708                 obj=x.get();
709                 return *this;
710         }
711
712         //! Swaps the values of two handles without reference counts
713         loose_handle<value_type> &
714         swap(loose_handle<value_type> &x)
715         {
716                 pointer ptr=x.obj;
717                 x.obj=x.get();
718                 obj=ptr;
719                 return *this;
720         }
721
722         //! Handle release procedure
723         void detach() { obj=0;  }
724
725         // This will be reintroduced with a new function
726         //void release() { detach(); }
727
728         void reset() { detach(); }
729
730         bool empty()const { return obj==0; }
731
732         handle<value_type> clone()const { assert(obj); return obj->clone(); }
733
734         //! Returns a constant handle to our object
735         loose_handle<const value_type> constant()const { return *this; }
736
737         //! Returns number of instances
738         count_type
739         count()const
740                 { return obj?obj->count():0; }
741
742         reference
743         operator*()const
744                 { assert(obj); return *obj; }
745
746         pointer
747         operator->()const
748                 { assert(obj); return obj; }
749
750         //! static_cast<> overload
751         //template <class U>
752         //operator loose_handle<U>()const
753         //{ return loose_handle<U>(static_cast<U*>(obj)); }
754
755         //! static_cast<> overload (for consts)
756         operator loose_handle<const value_type>()const
757         { return loose_handle<const value_type>(static_cast<const_pointer>(obj)); }
758
759         operator handle<value_type>()const
760         { return handle<value_type>(obj); }
761
762         operator rhandle<value_type>()const
763         { return rhandle<value_type>(obj); }
764
765         //! Returns pointer to the object that is being wrapped
766         pointer get()const { return obj; }
767
768         //! More explicit bool cast
769         operator bool()const
770                 { return obj!=0; }
771
772         bool
773         operator!()const
774                 { return !obj; }
775
776         void ref() { if(obj)obj->ref(); }
777
778         bool unref() { if(obj && !obj->unref()){ obj=0; return false; } return true; }
779 }; // END of template class loose_handle
780
781 // cast loose_handle<> -> handle<>
782 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())); }
783 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())); }
784 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())); }
785 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())); }
786
787 // cast rhandle_handle<> -> handle<>
788 template <class T> template <class U> handle<T> handle<T>::cast_static     (const rhandle<U>&      x) { return handle<T>(static_cast     <T*>(x.get())); }
789 template <class T> template <class U> handle<T> handle<T>::cast_dynamic    (const rhandle<U>&      x) { return handle<T>(dynamic_cast    <T*>(x.get())); }
790 template <class T> template <class U> handle<T> handle<T>::cast_const      (const rhandle<U>&      x) { return handle<T>(const_cast              <T*>(x.get())); }
791 template <class T> template <class U> handle<T> handle<T>::cast_reinterpret(const rhandle<U>&      x) { return handle<T>(reinterpret_cast<T*>(x.get())); }
792
793 // cast U* -> handle<>
794 template <class T> template <class U> handle<T> handle<T>::cast_static     (U*                                     x) { return handle<T>(static_cast     <T*>(x));               }
795 template <class T> template <class U> handle<T> handle<T>::cast_dynamic    (U*                                     x) { return handle<T>(dynamic_cast    <T*>(x));               }
796 template <class T> template <class U> handle<T> handle<T>::cast_const      (U*                                     x) { return handle<T>(const_cast              <T*>(x));               }
797 template <class T> template <class U> handle<T> handle<T>::cast_reinterpret(U*                                     x) { return handle<T>(reinterpret_cast<T*>(x));               }
798
799 // operator== for handle<>, loose_handle<> and T*
800 template <class T,class U> bool operator==(const handle          <T>& lhs,const handle          <U>& rhs) { return (lhs.get()==rhs.get()); }
801 template <class T,class U> bool operator==(const loose_handle<T>& lhs,const loose_handle<U>& rhs) { return (lhs.get()==rhs.get()); }
802 template <class T,class U> bool operator==(const handle          <T>& lhs,const loose_handle<U>& rhs) { return (lhs.get()==rhs.get()); }
803 template <class T,class U> bool operator==(const loose_handle<T>& lhs,const handle              <U>& rhs) { return (lhs.get()==rhs.get()); }
804 template <class T>                 bool operator==(const handle<T>&               lhs,const T*                           rhs) { return (lhs.get()==rhs);           }
805 template <class T>                 bool operator==(const loose_handle<T>& lhs,const T*                           rhs) { return (lhs.get()==rhs);           }
806 template <class T>                 bool operator==(const T*                               lhs,const handle<T>&           rhs) { return (lhs              ==rhs.get()); }
807 template <class T>                 bool operator==(const T*                               lhs,const loose_handle<T>& rhs) { return (lhs          ==rhs.get()); }
808
809 // operator!= for handle<>, loose_handle<> and T*
810 template <class T,class U> bool operator!=(const handle          <T>& lhs,const handle          <U>& rhs) { return (lhs.get()!=rhs.get()); }
811 template <class T,class U> bool operator!=(const loose_handle<T>& lhs,const loose_handle<U>& rhs) { return (lhs.get()!=rhs.get()); }
812 template <class T,class U> bool operator!=(const handle          <T>& lhs,const loose_handle<U>& rhs) { return (lhs.get()!=rhs.get()); }
813 template <class T,class U> bool operator!=(const loose_handle<T>& lhs,const handle              <U>& rhs) { return (lhs.get()!=rhs.get()); }
814 template <class T>                 bool operator!=(const handle<T>&               lhs,const T*                           rhs) { return (lhs.get()!=rhs);           }
815 template <class T>                 bool operator!=(const loose_handle<T>& lhs,const T*                           rhs) { return (lhs.get()!=rhs);           }
816 template <class T>                 bool operator!=(const T*                               lhs,const handle<T>&           rhs) { return (lhs              !=rhs.get()); }
817 template <class T>                 bool operator!=(const T*                               lhs,const loose_handle<T>& rhs) { return (lhs          !=rhs.get()); }
818
819 // operator< for handle<>, loose_handle<> and T*
820 template <class T,class U> bool operator<(const handle<T>&                lhs,const handle<U>&           rhs) { return (lhs.get()<rhs.get());  }
821 template <class T,class U> bool operator<(const loose_handle<T>&  lhs,const loose_handle<U>& rhs) { return (lhs.get()<rhs.get());  }
822 template <class T,class U> bool operator<(const handle<T>&                lhs,const loose_handle<U>& rhs) { return (lhs.get()<rhs.get());  }
823 template <class T,class U> bool operator<(const loose_handle<T>&  lhs,const handle<U>&           rhs) { return (lhs.get()<rhs.get());  }
824 template <class T>                 bool operator<(const handle<T>&                lhs,const T*                           rhs) { return (lhs.get()<rhs);            }
825 template <class T>                 bool operator<(const loose_handle<T>&  lhs,const T*                           rhs) { return (lhs.get()<rhs);            }
826 template <class T>                 bool operator<(const T*                                lhs,const handle<T>&           rhs) { return (lhs              <rhs.get());  }
827 template <class T>                 bool operator<(const T*                                lhs,const loose_handle<T>& rhs) { return (lhs          <rhs.get());  }
828
829 _ETL_END_NAMESPACE
830
831 /* === E N D =============================================================== */
832
833 #endif