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