1 ////////////////////////////////////////////////////////////////////////////////
2 // The Loki Library
3 // Copyright (c) 2001 by Andrei Alexandrescu
4 // This code accompanies the book:
5 // Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design
6 // Patterns Applied". Copyright (c) 2001. Addison-Wesley.
7 // Permission to use, copy, modify, distribute and sell this software for any
8 // purpose is hereby granted without fee, provided that the above copyright
9 // notice appear in all copies and that both that copyright notice and this
10 // permission notice appear in supporting documentation.
11 // The author or Addison-Welsey Longman make no representations about the
12 // suitability of this software for any purpose. It is provided "as is"
13 // without express or implied warranty.
14 ////////////////////////////////////////////////////////////////////////////////
15
16 // Last update: June 20, 2001
17
18 #ifndef SMARTPTR_INC_
19 #define SMARTPTR_INC_
20
21 ////////////////////////////////////////////////////////////////////////////////
22 // IMPORTANT NOTE
23 // Due to threading issues, the OwnershipPolicy has been changed as follows:
24 // Release() returns a boolean saying if that was the last release
25 // so the pointer can be deleted by the StoragePolicy
26 // IsUnique() was removed
27 ////////////////////////////////////////////////////////////////////////////////
28
29
30 #include "SmallObj.h"
31 #include "TypeManip.h"
32 #include "static_check.h"
33 #include <functional>
34 #include <stdexcept>
35
36 namespace Loki
37 {
38
39 ////////////////////////////////////////////////////////////////////////////////
40 // class template DefaultSPStorage
41 // Implementation of the StoragePolicy used by SmartPtr
42 ////////////////////////////////////////////////////////////////////////////////
43
44 template <class T>
45 class DefaultSPStorage
46 {
47 protected:
48 typedef T* StoredType; // the type of the pointee_ object
49 typedef T* PointerType; // type returned by operator->
50 typedef T& ReferenceType; // type returned by operator*
51
52 public:
53 DefaultSPStorage() : pointee_(Default())
54 {}
55
56 // The storage policy doesn't initialize the stored pointer
57 // which will be initialized by the OwnershipPolicy's Clone fn
58 DefaultSPStorage(const DefaultSPStorage&)
59 {}
60
61 template <class U>
62 DefaultSPStorage(const DefaultSPStorage<U>&)
63 {}
64
65 DefaultSPStorage(const StoredType& p) : pointee_(p) {}
66
67 PointerType operator->() const { return pointee_; }
68
69 ReferenceType operator*() const { return *pointee_; }
70
71 void Swap(DefaultSPStorage& rhs)
72 { std::swap(pointee_, rhs.pointee_); }
73
74 // Accessors
75 friend inline PointerType GetImpl(const DefaultSPStorage& sp)
76 { return sp.pointee_; }
77
78 friend inline const StoredType& GetImplRef(const DefaultSPStorage& sp)
79 { return sp.pointee_; }
80
81 friend inline StoredType& GetImplRef(DefaultSPStorage& sp)
82 { return sp.pointee_; }
83
84 protected:
85 // Destroys the data stored
86 // (Destruction might be taken over by the OwnershipPolicy)
87 void Destroy()
88 { delete pointee_; }
89
90 // Default value to initialize the pointer
91 static StoredType Default()
92 { return 0; }
93
94 private:
95 // Data
96 StoredType pointee_;
97 };
98
99 ////////////////////////////////////////////////////////////////////////////////
100 // class template RefCounted
101 // Implementation of the OwnershipPolicy used by SmartPtr
102 // Provides a classic external reference counting implementation
103 ////////////////////////////////////////////////////////////////////////////////
104
105 template <class P>
106 class RefCounted
107 {
108 public:
109 RefCounted()
110 {
111 pCount_ = static_cast<unsigned int*>(
112 SmallObject<>::operator new(sizeof(unsigned int)));
113 assert(pCount_);
114 *pCount_ = 1;
115 }
116
117 RefCounted(const RefCounted& rhs)
118 : pCount_(rhs.pCount_)
119 {}
120
121 // MWCW lacks template friends, hence the following kludge
122 template <typename P1>
123 RefCounted(const RefCounted<P1>& rhs)
124 : pCount_(reinterpret_cast<const RefCounted&>(rhs).pCount_)
125 {}
126
127 P Clone(const P& val)
128 {
129 ++*pCount_;
130 return val;
131 }
132
133 bool Release(const P&)
134 {
135 if (!--*pCount_)
136 {
137 SmallObject<>::operator delete(pCount_, sizeof(unsigned int));
138 return true;
139 }
140 return false;
141 }
142
143 void Swap(RefCounted& rhs)
144 { std::swap(pCount_, rhs.pCount_); }
145
146 enum { destructiveCopy = false };
147
148 private:
149 // Data
150 unsigned int* pCount_;
151 };
152
153 ////////////////////////////////////////////////////////////////////////////////
154 // class template RefCountedMT
155 // Implementation of the OwnershipPolicy used by SmartPtr
156 // Implements external reference counting for multithreaded programs
157 ////////////////////////////////////////////////////////////////////////////////
158 template <class P,
159 template <class> class ThreadingModel>
160 class RefCountedMT : public ThreadingModel< RefCountedMT<P, ThreadingModel> >
161 {
162 public:
163 RefCountedMT()
164 {
165 pCount_ = static_cast<unsigned int*>(
166 SmallObject<ThreadingModel>::operator new(
167 sizeof(unsigned int)));
168 assert(pCount_);
169 *pCount_ = 1;
170 }
171
172 RefCountedMT(const RefCountedMT& rhs)
173 : pCount_(rhs.pCount_)
174 {}
175
176 // MWCW lacks template friends, hence the following kludge
177 template <typename P1>
178 RefCountedMT(const RefCountedMT<P1, ThreadingModel>& rhs)
179 : pCount_(reinterpret_cast<const RefCounted<P>&>(rhs).pCount_)
180 {}
181
182 P Clone(const P& val)
183 {
184 ThreadingModel<RefCountedMT>::AtomicIncrement(*pCount_);
185 return val;
186 }
187
188 bool Release(const P&)
189 {
190 if (!ThreadingModel<RefCountedMT>::AtomicDecrement(*pCount_))
191 {
192 SmallObject<ThreadingModel>::operator delete(pCount_,
193 sizeof(unsigned int));
194 return true;
195 }
196 return false;
197 }
198
199 void Swap(RefCountedMT& rhs)
200 { std::swap(pCount_, rhs.pCount_); }
201
202 enum { destructiveCopy = false };
203
204 private:
205 // Data
206 volatile unsigned int* pCount_;
207 };
208
209 ////////////////////////////////////////////////////////////////////////////////
210 // class template COMRefCounted
211 // Implementation of the OwnershipPolicy used by SmartPtr
212 // Adapts COM intrusive reference counting to OwnershipPolicy-specific syntax
213 ////////////////////////////////////////////////////////////////////////////////
214
215 template <class P>
216 class COMRefCounted
217 {
218 public:
219 COMRefCounted()
220 {}
221
222 template <class U>
223 COMRefCounted(const COMRefCounted<U>&)
224 {}
225
226 static P Clone(const P& val)
227 {
228 val->AddRef();
229 return val;
230 }
231
232 static bool Release(const P& val)
233 { val->Release(); return false; }
234
235 enum { destructiveCopy = false };
236
237 static void Swap(COMRefCounted&)
238 {}
239 };
240
241 ////////////////////////////////////////////////////////////////////////////////
242 // class template DeepCopy
243 // Implementation of the OwnershipPolicy used by SmartPtr
244 // Implements deep copy semantics, assumes existence of a Clone() member
245 // function of the pointee type
246 ////////////////////////////////////////////////////////////////////////////////
247
248 template <class P>
249 struct DeepCopy
250 {
251 DeepCopy()
252 {}
253
254 template <class P1>
255 DeepCopy(const DeepCopy<P1>&)
256 {}
257
258 static P Clone(const P& val)
259 { return val->Clone(); }
260
261 static bool Release(const P& val)
262 { return true; }
263
264 static void Swap(DeepCopy&)
265 {}
266
267 enum { destructiveCopy = false };
268 };
269
270 ////////////////////////////////////////////////////////////////////////////////
271 // class template RefLinked
272 // Implementation of the OwnershipPolicy used by SmartPtr
273 // Implements reference linking
274 ////////////////////////////////////////////////////////////////////////////////
275
276 namespace Private
277 {
278 class RefLinkedBase
279 {
280 public:
281 RefLinkedBase()
282 { prev_ = next_ = this; }
283
284 RefLinkedBase(const RefLinkedBase& rhs)
285 {
286 prev_ = &rhs;
287 next_ = rhs.next_;
288 prev_->next_ = this;
289 next_->prev_ = this;
290 }
291
292 bool Release()
293 {
294 if (next_ == this)
295 {
296 assert(prev_ == this);
297 return true;
298 }
299 prev_->next_ = next_;
300 next_->prev_ = prev_;
301 return false;
302 }
303
304 void Swap(RefLinkedBase& rhs)
305 {
306 if (next_ == this)
307 {
308 assert(prev_ == this);
309 if (rhs.next_ == &rhs)
310 {
311 assert(rhs.prev_ == &rhs);
312 // both lists are empty, nothing 2 do
313 return;
314 }
315 prev_ = rhs.prev_;
316 next_ = rhs.next_;
317 prev_->next_ = next_->prev_ = this;
318 rhs.next_ = rhs.prev_ = &rhs;
319 return;
320 }
321 if (rhs.next_ == &rhs)
322 {
323 rhs.Swap(*this);
324 return;
325 }
326 std::swap(prev_, rhs.prev_);
327 std::swap(next_, rhs.next_);
328 std::swap(prev_->next_, rhs.prev_->next_);
329 std::swap(next_->prev_, rhs.next_->prev_);
330 }
331
332 enum { destructiveCopy = false };
333
334 private:
335 mutable const RefLinkedBase* prev_;
336 mutable const RefLinkedBase* next_;
337 };
338 }
339
340 template <class P>
341 class RefLinked : public Private::RefLinkedBase
342 {
343 public:
344 RefLinked()
345 {}
346
347 template <class P1>
348 RefLinked(const RefLinked<P1>& rhs)
349 : Private::RefLinkedBase(rhs)
350 {}
351
352 static P Clone(const P& val)
353 { return val; }
354
355 bool Release(const P&)
356 { return Private::RefLinkedBase::Release(); }
357 };
358
359 ////////////////////////////////////////////////////////////////////////////////
360 // class template DestructiveCopy
361 // Implementation of the OwnershipPolicy used by SmartPtr
362 // Implements destructive copy semantics (a la std::auto_ptr)
363 ////////////////////////////////////////////////////////////////////////////////
364
365 template <class P>
366 class DestructiveCopy
367 {
368 public:
369 DestructiveCopy()
370 {}
371
372 template <class P1>
373 DestructiveCopy(const DestructiveCopy<P1>&)
374 {}
375
376 template <class P1>
377 static P Clone(P1& val)
378 {
379 P result(val);
380 val = P1();
381 return result;
382 }
383
384 static bool Release(const P&)
385 { return true; }
386
387 static void Swap(DestructiveCopy&)
388 {}
389
390 enum { destructiveCopy = true };
391 };
392
393 ////////////////////////////////////////////////////////////////////////////////
394 // class template NoCopy
395 // Implementation of the OwnershipPolicy used by SmartPtr
396 // Implements a policy that doesn't allow copying objects
397 ////////////////////////////////////////////////////////////////////////////////
398
399 template <class P>
400 class NoCopy
401 {
402 public:
403 NoCopy()
404 {}
405
406 template <class P1>
407 NoCopy(const NoCopy<P1>&)
408 {}
409
410 static P Clone(const P&)
411 {
412 CT_ASSERT(false, This_Policy_Disallows_Value_Copying);
413 }
414
415 static bool Release(const P&)
416 { return true; }
417
418 static void Swap(NoCopy&)
419 {}
420
421 enum { destructiveCopy = false };
422 };
423
424 ////////////////////////////////////////////////////////////////////////////////
425 // class template AllowConversion
426 // Implementation of the ConversionPolicy used by SmartPtr
427 // Allows implicit conversion from SmartPtr to the pointee type
428 ////////////////////////////////////////////////////////////////////////////////
429
430 struct AllowConversion
431 {
432 enum { allow = true };
433
434 void Swap(AllowConversion&)
435 {}
436 };
437
438 ////////////////////////////////////////////////////////////////////////////////
439 // class template DisallowConversion
440 // Implementation of the ConversionPolicy used by SmartPtr
441 // Does not allow implicit conversion from SmartPtr to the pointee type
442 // You can initialize a DisallowConversion with an AllowConversion
443 ////////////////////////////////////////////////////////////////////////////////
444
445 struct DisallowConversion
446 {
447 DisallowConversion()
448 {}
449
450 DisallowConversion(const AllowConversion&)
451 {}
452
453 enum { allow = false };
454
455 void Swap(DisallowConversion&)
456 {}
457 };
458
459 ////////////////////////////////////////////////////////////////////////////////
460 // class template NoCheck
461 // Implementation of the CheckingPolicy used by SmartPtr
462 // Well, it's clear what it does :o)
463 ////////////////////////////////////////////////////////////////////////////////
464
465 template <class P>
466 struct NoCheck
467 {
468 NoCheck()
469 {}
470
471 template <class P1>
472 NoCheck(const NoCheck<P1>&)
473 {}
474
475 static void OnDefault(const P&)
476 {}
477
478 static void OnInit(const P&)
479 {}
480
481 static void OnDereference(const P&)
482 {}
483
484 static void Swap(NoCheck&)
485 {}
486 };
487
488
489 ////////////////////////////////////////////////////////////////////////////////
490 // class template AssertCheck
491 // Implementation of the CheckingPolicy used by SmartPtr
492 // Checks the pointer before dereference
493 ////////////////////////////////////////////////////////////////////////////////
494
495 template <class P>
496 struct AssertCheck
497 {
498 AssertCheck()
499 {}
500
501 template <class P1>
502 AssertCheck(const AssertCheck<P1>&)
503 {}
504
505 template <class P1>
506 AssertCheck(const NoCheck<P1>&)
507 {}
508
509 static void OnDefault(const P&)
510 {}
511
512 static void OnInit(const P&)
513 {}
514
515 static void OnDereference(P val)
516 { assert(val); }
517
518 static void Swap(AssertCheck&)
519 {}
520 };
521
522 ////////////////////////////////////////////////////////////////////////////////
523 // class template AssertCheckStrict
524 // Implementation of the CheckingPolicy used by SmartPtr
525 // Checks the pointer against zero upon initialization and before dereference
526 // You can initialize an AssertCheckStrict with an AssertCheck
527 ////////////////////////////////////////////////////////////////////////////////
528
529 template <class P>
530 struct AssertCheckStrict
531 {
532 AssertCheckStrict()
533 {}
534
535 template <class U>
536 AssertCheckStrict(const AssertCheckStrict<U>&)
537 {}
538
539 template <class U>
540 AssertCheckStrict(const AssertCheck<U>&)
541 {}
542
543 template <class P1>
544 AssertCheckStrict(const NoCheck<P1>&)
545 {}
546
547 static void OnDefault(P val)
548 { assert(val); }
549
550 static void OnInit(P val)
551 { assert(val); }
552
553 static void OnDereference(P val)
554 { assert(val); }
555
556 static void Swap(AssertCheckStrict&)
557 {}
558 };
559
560 ////////////////////////////////////////////////////////////////////////////////
561 // class NullPointerException
562 // Used by some implementations of the CheckingPolicy used by SmartPtr
563 ////////////////////////////////////////////////////////////////////////////////
564
565 struct NullPointerException : public std::runtime_error
566 {
567 NullPointerException() : std::runtime_error("")
568 { }
569 const char* what() const
570 { return "Null Pointer Exception"; }
571 };
572
573 ////////////////////////////////////////////////////////////////////////////////
574 // class template RejectNullStatic
575 // Implementation of the CheckingPolicy used by SmartPtr
576 // Checks the pointer upon initialization and before dereference
577 ////////////////////////////////////////////////////////////////////////////////
578
579 template <class P>
580 struct RejectNullStatic
581 {
582 RejectNullStatic()
583 {}
584
585 template <class P1>
586 RejectNullStatic(const RejectNullStatic<P1>&)
587 {}
588
589 template <class P1>
590 RejectNullStatic(const NoCheck<P1>&)
591 {}
592
593 template <class P1>
594 RejectNullStatic(const AssertCheck<P1>&)
595 {}
596
597 template <class P1>
598 RejectNullStatic(const AssertCheckStrict<P1>&)
599 {}
600
601 static void OnDefault(const P&)
602 {
603 CompileTimeError<false>
604 ERROR_This_Policy_Does_Not_Allow_Default_Initialization;
605 }
606
607 static void OnInit(const P& val)
608 { if (!val) throw NullPointerException(); }
609
610 static void OnDereference(const P& val)
611 { if (!val) throw NullPointerException(); }
612
613 static void Swap(RejectNullStatic&)
614 {}
615 };
616
617 ////////////////////////////////////////////////////////////////////////////////
618 // class template RejectNull
619 // Implementation of the CheckingPolicy used by SmartPtr
620 // Checks the pointer before dereference
621 ////////////////////////////////////////////////////////////////////////////////
622
623 template <class P>
624 struct RejectNull
625 {
626 RejectNull()
627 {}
628
629 template <class P1>
630 RejectNull(const RejectNull<P1>&)
631 {}
632
633 static void OnInit(P val)
634 { if (!val) throw NullPointerException(); }
635
636 static void OnDefault(P val)
637 { OnInit(val); }
638
639 void OnDereference(P val)
640 { OnInit(val); }
641
642 void Swap(RejectNull&)
643 {}
644 };
645
646 ////////////////////////////////////////////////////////////////////////////////
647 // class template RejectNullStrict
648 // Implementation of the CheckingPolicy used by SmartPtr
649 // Checks the pointer upon initialization and before dereference
650 ////////////////////////////////////////////////////////////////////////////////
651
652 template <class P>
653 struct RejectNullStrict
654 {
655 RejectNullStrict()
656 {}
657
658 template <class P1>
659 RejectNullStrict(const RejectNullStrict<P1>&)
660 {}
661
662 template <class P1>
663 RejectNullStrict(const RejectNull<P1>&)
664 {}
665
666 static void OnInit(P val)
667 { if (!val) throw NullPointerException(); }
668
669 void OnDereference(P val)
670 { OnInit(val); }
671
672 void Swap(RejectNullStrict&)
673 {}
674 };
675
676 ////////////////////////////////////////////////////////////////////////////////
677 // class template ByRef
678 // Transports a reference as a value
679 // Serves to implement the Colvin/Gibbons trick for SmartPtr
680 ////////////////////////////////////////////////////////////////////////////////
681
682 template <class T>
683 class ByRef
684 {
685 public:
686 ByRef(T& v) : value_(v) {}
687 operator T&() { return value_; }
688 // gcc doesn't like this:
689 // operator const T&() const { return value_; }
690 private:
691 T& value_;
692 };
693
694 ////////////////////////////////////////////////////////////////////////////////
695 // class template SmartPtr (declaration)
696 // The reason for all the fuss above
697 ////////////////////////////////////////////////////////////////////////////////
698
699 template
700 <
701 typename T,
702 template <class> class OwnershipPolicy = RefCounted,
703 class ConversionPolicy = DisallowConversion,
704 template <class> class CheckingPolicy = AssertCheck,
705 template <class> class StoragePolicy = DefaultSPStorage
706 >
707 class SmartPtr;
708
709 ////////////////////////////////////////////////////////////////////////////////
710 // class template SmartPtr (definition)
711 ////////////////////////////////////////////////////////////////////////////////
712
713 template
714 <
715 typename T,
716 template <class> class OwnershipPolicy,
717 class ConversionPolicy,
718 template <class> class CheckingPolicy,
719 template <class> class StoragePolicy
720 >
721 class SmartPtr
722 : public StoragePolicy<T>
723 , public OwnershipPolicy<typename StoragePolicy<T>::PointerType>
724 , public CheckingPolicy<typename StoragePolicy<T>::StoredType>
725 , public ConversionPolicy
726 {
727 typedef StoragePolicy<T> SP;
728 typedef OwnershipPolicy<typename StoragePolicy<T>::PointerType> OP;
729 typedef CheckingPolicy<typename StoragePolicy<T>::StoredType> KP;
730 typedef ConversionPolicy CP;
731
732 public:
733 typedef typename SP::PointerType PointerType;
734 typedef typename SP::StoredType StoredType;
735 typedef typename SP::ReferenceType ReferenceType;
736
737 typedef typename Select<OP::destructiveCopy,
738 SmartPtr, const SmartPtr>::Result
739 CopyArg;
740
741 SmartPtr()
742 { KP::OnDefault(GetImpl(*this)); }
743
744 SmartPtr(const StoredType& p) : SP(p)
745 { KP::OnInit(GetImpl(*this)); }
746
747 SmartPtr(CopyArg& rhs)
748 : SP(rhs), OP(rhs), KP(rhs), CP(rhs)
749 { GetImplRef(*this) = OP::Clone(GetImplRef(rhs)); }
750
751 template
752 <
753 typename T1,
754 template <class> class OP1,
755 class CP1,
756 template <class> class KP1,
757 template <class> class SP1
758 >
759 SmartPtr(const SmartPtr<T1, OP1, CP1, KP1, SP1>& rhs)
760 : SP(rhs), OP(rhs), KP(rhs), CP(rhs)
761 { GetImplRef(*this) = OP::Clone(GetImplRef(rhs)); }
762
763 template
764 <
765 typename T1,
766 template <class> class OP1,
767 class CP1,
768 template <class> class KP1,
769 template <class> class SP1
770 >
771 SmartPtr(SmartPtr<T1, OP1, CP1, KP1, SP1>& rhs)
772 : SP(rhs), OP(rhs), KP(rhs), CP(rhs)
773 { GetImplRef(*this) = OP::Clone(GetImplRef(rhs)); }
774
775 SmartPtr(ByRef<SmartPtr> rhs)
776 : SP(rhs), OP(rhs), KP(rhs), CP(rhs)
777 {}
778
779 operator ByRef<SmartPtr>()
780 { return ByRef<SmartPtr>(*this); }
781
782 SmartPtr& operator=(CopyArg& rhs)
783 {
784 SmartPtr temp(rhs);
785 temp.Swap(*this);
786 return *this;
787 }
788
789 template
790 <
791 typename T1,
792 template <class> class OP1,
793 class CP1,
794 template <class> class KP1,
795 template <class> class SP1
796 >
797 SmartPtr& operator=(const SmartPtr<T1, OP1, CP1, KP1, SP1>& rhs)
798 {
799 SmartPtr temp(rhs);
800 temp.Swap(*this);
801 return *this;
802 }
803
804 template
805 <
806 typename T1,
807 template <class> class OP1,
808 class CP1,
809 template <class> class KP1,
810 template <class> class SP1
811 >
812 SmartPtr& operator=(SmartPtr<T1, OP1, CP1, KP1, SP1>& rhs)
813 {
814 SmartPtr temp(rhs);
815 temp.Swap(*this);
816 return *this;
817 }
818
819 void Swap(SmartPtr& rhs)
820 {
821 OP::Swap(rhs);
822 CP::Swap(rhs);
823 KP::Swap(rhs);
824 SP::Swap(rhs);
825 }
826
827 ~SmartPtr()
828 {
829 if (OP::Release(GetImpl(*static_cast<SP*>(this))))
830 {
831 SP::Destroy();
832 }
833 }
834
835 friend inline void Release(SmartPtr& sp, typename SP::StoredType& p)
836 {
837 p = GetImplRef(sp);
838 GetImplRef(sp) = SP::Default();
839 }
840
841 friend inline void Reset(SmartPtr& sp, typename SP::StoredType p)
842 { SmartPtr(p).Swap(sp); }
843
844 PointerType operator->()
845 {
846 KP::OnDereference(GetImplRef(*this));
847 return SP::operator->();
848 }
849
850 PointerType operator->() const
851 {
852 KP::OnDereference(GetImplRef(*this));
853 return SP::operator->();
854 }
855
856 ReferenceType operator*()
857 {
858 KP::OnDereference(GetImplRef(*this));
859 return SP::operator*();
860 }
861
862 ReferenceType operator*() const
863 {
864 KP::OnDereference(GetImplRef(*this));
865 return SP::operator*();
866 }
867
868 bool operator!() const // Enables "if (!sp) ..."
869 { return GetImpl(*this) == 0; }
870
871 inline friend bool operator==(const SmartPtr& lhs,
872 const T* rhs)
873 { return GetImpl(lhs) == rhs; }
874
875 inline friend bool operator==(const T* lhs,
876 const SmartPtr& rhs)
877 { return rhs == lhs; }
878
879 inline friend bool operator!=(const SmartPtr& lhs,
880 const T* rhs)
881 { return !(lhs == rhs); }
882
883 inline friend bool operator!=(const T* lhs,
884 const SmartPtr& rhs)
885 { return rhs != lhs; }
886
887 // Ambiguity buster
888 template
889 <
890 typename T1,
891 template <class> class OP1,
892 class CP1,
893 template <class> class KP1,
894 template <class> class SP1
895 >
896 bool operator==(const SmartPtr<T1, OP1, CP1, KP1, SP1>& rhs) const
897 { return *this == GetImpl(rhs); }
898
899 // Ambiguity buster
900 template
901 <
902 typename T1,
903 template <class> class OP1,
904 class CP1,
905 template <class> class KP1,
906 template <class> class SP1
907 >
908 bool operator!=(const SmartPtr<T1, OP1, CP1, KP1, SP1>& rhs) const
909 { return !(*this == rhs); }
910
911 // Ambiguity buster
912 template
913 <
914 typename T1,
915 template <class> class OP1,
916 class CP1,
917 template <class> class KP1,
918 template <class> class SP1
919 >
920 bool operator<(const SmartPtr<T1, OP1, CP1, KP1, SP1>& rhs) const
921 { return *this < GetImpl(rhs); }
922
923 private:
924 // Helper for enabling 'if (sp)'
925 struct Tester
926 {
927 Tester() {}
928 private:
929 void operator delete(void*);
930 };
931
932 public:
933 // enable 'if (sp)'
934 operator Tester*() const
935 {
936 if (!*this) return 0;
937 static Tester t;
938 return &t;
939 }
940
941 private:
942 // Helper for disallowing automatic conversion
943 struct Insipid
944 {
945 Insipid(PointerType) {}
946 };
947
948 typedef typename Select<CP::allow, PointerType, Insipid>::Result
949 AutomaticConversionResult;
950
951 public:
952 operator AutomaticConversionResult() const
953 { return GetImpl(*this); }
954 };
955
956 ////////////////////////////////////////////////////////////////////////////////
957 // free comparison operators for class template SmartPtr
958 ////////////////////////////////////////////////////////////////////////////////
959
960 ////////////////////////////////////////////////////////////////////////////////
961 // operator== for lhs = SmartPtr, rhs = raw pointer
962 ////////////////////////////////////////////////////////////////////////////////
963
964 template
965 <
966 typename T,
967 template <class> class OP,
968 class CP,
969 template <class> class KP,
970 template <class> class SP,
971 typename U
972 >
973 inline bool operator==(const SmartPtr<T, OP, CP, KP, SP>& lhs,
974 const U* rhs)
975 { return GetImpl(lhs) == rhs; }
976
977 ////////////////////////////////////////////////////////////////////////////////
978 // operator== for lhs = raw pointer, rhs = SmartPtr
979 ////////////////////////////////////////////////////////////////////////////////
980
981 template
982 <
983 typename T,
984 template <class> class OP,
985 class CP,
986 template <class> class KP,
987 template <class> class SP,
988 typename U
989 >
990 inline bool operator==(const U* lhs,
991 const SmartPtr<T, OP, CP, KP, SP>& rhs)
992 { return rhs == lhs; }
993
994 ////////////////////////////////////////////////////////////////////////////////
995 // operator!= for lhs = SmartPtr, rhs = raw pointer
996 ////////////////////////////////////////////////////////////////////////////////
997
998 template
999 <
1000 typename T,
1001 template <class> class OP,
1002 class CP,
1003 template <class> class KP,
1004 template <class> class SP,
1005 typename U
1006 >
1007 inline bool operator!=(const SmartPtr<T, OP, CP, KP, SP>& lhs,
1008 const U* rhs)
1009 { return !(lhs == rhs); }
1010
1011 ////////////////////////////////////////////////////////////////////////////////
1012 // operator!= for lhs = raw pointer, rhs = SmartPtr
1013 ////////////////////////////////////////////////////////////////////////////////
1014
1015 template
1016 <
1017 typename T,
1018 template <class> class OP,
1019 class CP,
1020 template <class> class KP,
1021 template <class> class SP,
1022 typename U
1023 >
1024 inline bool operator!=(const U* lhs,
1025 const SmartPtr<T, OP, CP, KP, SP>& rhs)
1026 { return rhs != lhs; }
1027
1028 ////////////////////////////////////////////////////////////////////////////////
1029 // operator< for lhs = SmartPtr, rhs = raw pointer -- NOT DEFINED
1030 ////////////////////////////////////////////////////////////////////////////////
1031
1032 template
1033 <
1034 typename T,
1035 template <class> class OP,
1036 class CP,
1037 template <class> class KP,
1038 template <class> class SP,
1039 typename U
1040 >
1041 inline bool operator<(const SmartPtr<T, OP, CP, KP, SP>& lhs,
1042 const U* rhs);
1043
1044 ////////////////////////////////////////////////////////////////////////////////
1045 // operator< for lhs = raw pointer, rhs = SmartPtr -- NOT DEFINED
1046 ////////////////////////////////////////////////////////////////////////////////
1047
1048 template
1049 <
1050 typename T,
1051 template <class> class OP,
1052 class CP,
1053 template <class> class KP,
1054 template <class> class SP,
1055 typename U
1056 >
1057 inline bool operator<(const U* lhs,
1058 const SmartPtr<T, OP, CP, KP, SP>& rhs);
1059
1060 ////////////////////////////////////////////////////////////////////////////////
1061 // operator> for lhs = SmartPtr, rhs = raw pointer -- NOT DEFINED
1062 ////////////////////////////////////////////////////////////////////////////////
1063
1064 template
1065 <
1066 typename T,
1067 template <class> class OP,
1068 class CP,
1069 template <class> class KP,
1070 template <class> class SP,
1071 typename U
1072 >
1073 inline bool operator>(const SmartPtr<T, OP, CP, KP, SP>& lhs,
1074 const U* rhs)
1075 { return rhs < lhs; }
1076
1077 ////////////////////////////////////////////////////////////////////////////////
1078 // operator> for lhs = raw pointer, rhs = SmartPtr
1079 ////////////////////////////////////////////////////////////////////////////////
1080
1081 template
1082 <
1083 typename T,
1084 template <class> class OP,
1085 class CP,
1086 template <class> class KP,
1087 template <class> class SP,
1088 typename U
1089 >
1090 inline bool operator>(const U* lhs,
1091 const SmartPtr<T, OP, CP, KP, SP>& rhs)
1092 { return rhs < lhs; }
1093
1094 ////////////////////////////////////////////////////////////////////////////////
1095 // operator<= for lhs = SmartPtr, rhs = raw pointer
1096 ////////////////////////////////////////////////////////////////////////////////
1097
1098 template
1099 <
1100 typename T,
1101 template <class> class OP,
1102 class CP,
1103 template <class> class KP,
1104 template <class> class SP,
1105 typename U
1106 >
1107 inline bool operator<=(const SmartPtr<T, OP, CP, KP, SP>& lhs,
1108 const U* rhs)
1109 { return !(rhs < lhs); }
1110
1111 ////////////////////////////////////////////////////////////////////////////////
1112 // operator<= for lhs = raw pointer, rhs = SmartPtr
1113 ////////////////////////////////////////////////////////////////////////////////
1114
1115 template
1116 <
1117 typename T,
1118 template <class> class OP,
1119 class CP,
1120 template <class> class KP,
1121 template <class> class SP,
1122 typename U
1123 >
1124 inline bool operator<=(const U* lhs,
1125 const SmartPtr<T, OP, CP, KP, SP>& rhs)
1126 { return !(rhs < lhs); }
1127
1128 ////////////////////////////////////////////////////////////////////////////////
1129 // operator>= for lhs = SmartPtr, rhs = raw pointer
1130 ////////////////////////////////////////////////////////////////////////////////
1131
1132 template
1133 <
1134 typename T,
1135 template <class> class OP,
1136 class CP,
1137 template <class> class KP,
1138 template <class> class SP,
1139 typename U
1140 >
1141 inline bool operator>=(const SmartPtr<T, OP, CP, KP, SP>& lhs,
1142 const U* rhs)
1143 { return !(lhs < rhs); }
1144
1145 ////////////////////////////////////////////////////////////////////////////////
1146 // operator>= for lhs = raw pointer, rhs = SmartPtr
1147 ////////////////////////////////////////////////////////////////////////////////
1148
1149 template
1150 <
1151 typename T,
1152 template <class> class OP,
1153 class CP,
1154 template <class> class KP,
1155 template <class> class SP,
1156 typename U
1157 >
1158 inline bool operator>=(const U* lhs,
1159 const SmartPtr<T, OP, CP, KP, SP>& rhs)
1160 { return !(lhs < rhs); }
1161
1162 } // namespace Loki
1163
1164 ////////////////////////////////////////////////////////////////////////////////
1165 // specialization of std::less for SmartPtr
1166 ////////////////////////////////////////////////////////////////////////////////
1167
1168 namespace std
1169 {
1170 template
1171 <
1172 typename T,
1173 template <class> class OP,
1174 class CP,
1175 template <class> class KP,
1176 template <class> class SP
1177 >
1178 struct less< Loki::SmartPtr<T, OP, CP, KP, SP> >
1179 : public binary_function<Loki::SmartPtr<T, OP, CP, KP, SP>,
1180 Loki::SmartPtr<T, OP, CP, KP, SP>, bool>
1181 {
1182 bool operator()(const Loki::SmartPtr<T, OP, CP, KP, SP>& lhs,
1183 const Loki::SmartPtr<T, OP, CP, KP, SP>& rhs) const
1184 { return less<T*>()(GetImpl(lhs), GetImpl(rhs)); }
1185 };
1186 }
1187
1188 ////////////////////////////////////////////////////////////////////////////////
1189 // Change log:
1190 // June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!!
1191 ////////////////////////////////////////////////////////////////////////////////
1192
1193 #endif // SMARTPTR_INC_