Smart Pointers

smart_ptr.hpp

00001 #ifndef smart_ptr_HPP_HEADER_GUARD_
00002 #define smart_ptr_HPP_HEADER_GUARD_
00003 /*
00004 For more details, which include example usage, full introduction, parameters, and tutorial,
00005 see following link:
00006 http://axter.com/smartptr
00007 SET A SIDE NOTES:
00008 For ease of testing and distribution, all the policies are included in the same header with the smart_ptr.
00009 Once testing is near completion, the policies will be moved to separate header,  and the smart_ptr header 
00010 will have an #include to the new policy headers.
00011 
00012 This source file is documented in a Doxygen friendly format.
00013 This format allows Doxygen to pull the comments out, and to create help
00014 documents in HTML, RTF, man, and XML formats.
00015 http://www.stack.nl/~dimitri/doxygen/index.html
00016 */
00017 
00095 #ifndef __BORLANDC__ 
00096 #if !defined(_MSC_VER) || (_MSC_VER > 1200)
00097 //Both VC++6.0 and borland compilers don't support type defined via policy
00098 #define SMART_PTR_SUPPORT_RETURN_TYPE_THROUGH_POLICY_
00099 #endif
00100 #endif
00101 
00123 struct allocator_default_policy
00124 {
00134         template<typename T_obj> static inline T_obj* allocate(const T_obj* ptr)
00135         {
00136                 if (ptr) return new T_obj(*ptr);
00137                 return NULL;
00138         }
00142         template<typename T_obj> static inline void deallocate(T_obj* ptr){delete ptr;}
00143 };
00144 
00165 struct clone_function_allocator_policy
00166 {
00176         template<typename T_obj> static inline T_obj* allocate(const T_obj* ptr)
00177         {
00178                 if(!ptr) return NULL;
00179                 return static_cast<T_obj*>(ptr->do_clone());
00180         }
00184         template<typename T_obj> static inline void deallocate(T_obj* ptr){delete ptr;}
00185 };
00186 
00208 struct clone_static_function_allocator_policy
00209 {
00216         template<typename T_obj> static inline T_obj* allocate(const T_obj* ptr)
00217         {
00218                 if(!ptr) return NULL;
00219                 return T_obj::do_clone(*ptr);
00220         }
00224         template<typename T_obj> static inline void deallocate(T_obj* ptr){delete ptr;}
00225 };
00226 
00227 // @cond INCLUDE_ALL_OBJS_
00239 template<size_t size_array>
00240 struct allocator_array_policy
00241 {
00250         template<typename T_obj> static T_obj* allocate(const T_obj* ptr)
00251         {
00252                 if (!ptr) return NULL;
00253 #ifdef BOOST_ASSERT
00254                 BOOST_ASSERT(size_array);
00255 #endif //BOOST_ASSERT
00256                 T_obj *arr = new T_obj[size_array];
00257                 for(size_t i = 0;i < size_array;++i)
00258                         arr[i] = ptr[i];
00259                 return arr;
00260         }
00264         template<typename T_obj> static inline void deallocate(T_obj* ptr){delete[] ptr;}
00265 };
00266 // @endcond 
00267 
00283 struct value_comparsion_semantic_policy
00284 {
00285         template<class T1, class T2> static bool less_than(const T1 & a, const T2 & b){return (*a.c_ptr()) < (*b.c_ptr());}
00286         template<class T1, class T2> static bool greater_than(const T1 & a, const T2 & b){return (*a.c_ptr()) > (*b.c_ptr());}
00287         template<class T1, class T2> static bool less_than_or_equal(const T1 & a, const T2 & b){return (*a.c_ptr()) <= (*b.c_ptr());}
00288         template<class T1, class T2> static bool greater_than_or_equal(const T1 & a, const T2 & b){return (*a.c_ptr()) >= (*b.c_ptr());}
00289         template<class T1, class T2> static bool is_equal(const T1 & a, const T2 & b){return (*a.c_ptr()) == (*b.c_ptr());}
00290 };
00291 
00300 struct pointer_comparsion_semantic_policy
00301 {
00302         template<class T1, class T2> static bool less_than(const T1 & a, const T2 & b){return (a.c_ptr()) < (b.c_ptr());}
00303         template<class T1, class T2> static bool greater_than(const T1 & a, const T2 & b){return (a.c_ptr()) > (b.c_ptr());}
00304         template<class T1, class T2> static bool less_than_or_equal(const T1 & a, const T2 & b){return (a.c_ptr()) <= (b.c_ptr());}
00305         template<class T1, class T2> static bool greater_than_or_equal(const T1 & a, const T2 & b){return (a.c_ptr()) >= (b.c_ptr());}
00306         template<class T1, class T2> static bool is_equal(const T1 & a, const T2 & b){return (a.c_ptr()) == (b.c_ptr());}
00307 };
00308 
00315 struct no_comparsion_semantic_policy{};
00316 
00326 struct value_stream_operator_semantic_policy
00327 {
00328         template<class T1, class T2> static T1& input_stream(T1 &is, T2 &smart_pointer){is >> (*smart_pointer.get_ptr());return is;}
00329         template<class T1, class T2> static T1& output_stream(T1 &io, T2 &smart_pointer){io << (*smart_pointer.c_ptr());return io;}
00330 };
00331 
00339 struct no_stream_operator_semantic_policy{};
00340 
00356 struct value_arithmetic_semantic_policy
00357 {
00358         // @cond INCLUDE_ALL_OBJS_
00359         template<class T> struct return_type{typedef T type;};
00360         // @endcond
00361         template<class T1, class T2> static T1& plus_equal_smart_ptr(T1 & a, const T2 & b){a.get_ptr()->operator+=(*b.c_ptr());return a;}
00362         template<class T1, class T2> static T1& plus_equal(T1 & a, const T2 & b){a.get_ptr()->operator+=(b);return a;}
00363         template<class T1, class T2> static T1& minus_equal_smart_ptr(T1 & a, const T2 & b){a.get_ptr()->operator-=(*b.c_ptr());return a;}
00364         template<class T1, class T2> static T1& minus_equal(T1 & a, const T2 & b){a.get_ptr()->operator-=(b);return a;}
00365         template<class T1, class T2> static T1 plus(const T1 & a, const T2 & b)
00366         {
00367                 T1 c(a);
00368                 c.get_ptr()->operator+=(*b.c_ptr());
00369                 return c;
00370         }
00371         template<class T1, class T2> static T1 minus(const T1 & a, const T2 & b)
00372         {
00373                 T1 c(a);
00374                 c.get_ptr()->operator-=(*b.c_ptr());
00375                 return c;
00376         }
00377 };
00378 
00379 // @cond INCLUDE_ALL_OBJS_
00387 struct no_arithmetic_semantic_policy{template<class T>struct return_type{typedef T type;};};
00388 // @endcond
00389 
00413 class ref_link_policy
00414 {
00415         struct ref_link
00416         {
00417                 ref_link():m_back(NULL), m_front(NULL){}
00418                 ref_link *m_back;
00419                 ref_link *m_front;
00420         private:  //Disallow copy constructor and assignment op
00421                 ref_link(const ref_link&);
00422                 ref_link& operator=(const ref_link&);
00423         };
00424         ref_link m_ref_link;
00425         void pop_link()
00426         {
00427                 if (m_ref_link.m_back)
00428                 {
00429                         m_ref_link.m_back->m_front = m_ref_link.m_front;
00430                 }
00431                 if (m_ref_link.m_front)
00432                 {
00433                         m_ref_link.m_front->m_back = m_ref_link.m_back;
00434                 }
00435                 m_ref_link.m_front = NULL;
00436                 m_ref_link.m_back = NULL;
00437         }
00438         void insert_link(ref_link *Target)
00439         {
00440                 m_ref_link.m_back = Target;
00441                 m_ref_link.m_front = Target->m_front;
00442                 if (m_ref_link.m_front)
00443                 {
00444                         m_ref_link.m_front->m_back = &m_ref_link;
00445                 }
00446                 if (m_ref_link.m_back)
00447                 {
00448                         m_ref_link.m_back->m_front = &m_ref_link;
00449                 }
00450         }
00451         ref_link_policy(const ref_link_policy&);
00452         ref_link_policy& operator=(const ref_link_policy&);
00453 protected:
00454         template<class T>
00455                 inline bool is_referenced(T&)const{return (m_ref_link.m_back || m_ref_link.m_front);}
00456 public:
00457         ref_link_policy(){}
00458         template<class T1>
00459         inline ref_link_policy(ref_link_policy& src, T1&)
00460         {
00461                 insert_link(&src.m_ref_link);
00462         }
00463         template<class T, class F, class LCK>
00464                 void release(T& type, F clone_fct, LCK &lck_policy)
00465         {
00466                 if (!is_referenced(type)){
00467                         if (type && clone_fct)
00468                         {
00469                                 clone_fct(type, false, NULL, NULL, NULL);
00470                         }
00471                         type = NULL;
00472                 }
00473                 else
00474                 {
00475                         pop_link();
00476                         lck_policy.assignment_unlock_policy(type);
00477                 }
00478         }
00479         template<class T1, class F1, class T2, class F2, class LCK>
00480                 void assign(T1& type1, F1& clone_fct1, T2 type2, const F2 clone_fct2, ref_link_policy& src_policy, LCK &lck_policy)
00481         {
00482                 if (!type1 || type1 != type2)
00483                 {
00484                         lck_policy.assignment_lock_policy(type1);
00485                         const bool src_policy_eq_this = (this == &src_policy);
00486                         release(type1, clone_fct1, lck_policy);
00487                         type1 = type2;
00488                         clone_fct1 = clone_fct2;
00489                         if (src_policy_eq_this)
00490                         {
00491                                 m_ref_link.m_back = NULL;
00492                                 m_ref_link.m_front = NULL;
00493                         }
00494                         else
00495                                 insert_link(&src_policy.m_ref_link);
00496                 }
00497         }
00498 };
00499 
00523 class ref_count_policy
00524 {
00525         struct ref_count
00526         {
00527                 ref_count():m_count(new size_t(1)){}
00528                 ref_count(size_t *count_):m_count(count_){}
00529                 size_t *m_count;
00530         private:  //Disallow copy constructor and assignment op
00531                 ref_count(const ref_count&);
00532                 ref_count& operator=(const ref_count&);
00533         };
00534         ref_count m_ref_count;
00535         ref_count_policy(const ref_count_policy&);
00536         ref_count_policy& operator=(const ref_count_policy&);
00537 protected:
00538         template<class T>
00539                 inline bool is_referenced(T&)const{return (m_ref_count.m_count && (*m_ref_count.m_count) > 1);}
00540 public:
00541         ref_count_policy(){}
00542         template<class T1>
00543                 inline ref_count_policy(ref_count_policy& src, T1&):m_ref_count(src.m_ref_count.m_count)
00544         {
00545                 if (m_ref_count.m_count) ++(*m_ref_count.m_count);
00546         }
00548         template<class T, class F, class LCK>
00549                 void release(T& type, F clone_fct, LCK &lck_policy)
00550         {
00551                 if (!is_referenced(type)){
00552                         if (type && clone_fct)
00553                         {
00554                                 clone_fct(type, false, NULL, NULL, NULL);
00555                         }
00556                         type = NULL;
00557                         delete m_ref_count.m_count;
00558                         m_ref_count.m_count = NULL;
00559                 }
00560                 else
00561                 {
00562                         if (m_ref_count.m_count) --(*m_ref_count.m_count);
00563                         lck_policy.assignment_unlock_policy(type);
00564                 }
00565         }
00566         template<class T1, class F1, class T2, class F2, class LCK>
00567                 void assign(T1& type1, F1& clone_fct1, T2 type2, const F2 clone_fct2, ref_count_policy& src_policy, LCK &lck_policy)
00568         {
00569                 if (!type1 || type1 != type2)
00570                 {
00571                         lck_policy.assignment_lock_policy(type1);
00572                         const bool src_policy_eq_this = (this == &src_policy);
00573                         release(type1, clone_fct1, lck_policy);
00574                         type1 = type2;
00575                         clone_fct1 = clone_fct2;
00576                         if (src_policy_eq_this)
00577                                 m_ref_count.m_count = new size_t(0); //Set to zero, because of increment below
00578                         else
00579                                 m_ref_count.m_count = src_policy.m_ref_count.m_count;
00580                         if (m_ref_count.m_count) ++(*m_ref_count.m_count);
00581                 }
00582         }
00583 };
00584 
00611 class ref_intrusive_policy
00612 {
00613         ref_intrusive_policy(const ref_intrusive_policy&);
00614         ref_intrusive_policy& operator=(const ref_intrusive_policy&);
00615 protected:
00616         template<class T>
00617                 inline bool is_referenced(T& type)const{return intrusive_ptr_is_ref(type);}
00618 public:
00619         ref_intrusive_policy(){}
00620         template<class T>
00621         inline ref_intrusive_policy(ref_intrusive_policy&, T& type)
00622         {
00623                 if (type) intrusive_ptr_add_ref(type);
00624         }
00625         template<class T, class F, class LCK>
00626                 void release(T& type, F, LCK &)
00627         {
00628                 //intrusive_ptr_release must perform assignment_unlock_policy (unlock)
00629                 if (type) intrusive_ptr_release(type);
00630         }
00631         template<class T1, class F1, class T2, class F2, class LCK>
00632                 void assign(T1& type1, F1& clone_fct1, T2 type2, const F2 clone_fct2, ref_intrusive_policy &src_policy, LCK &lck_policy)
00633         {
00634                 if (!type1 || type1 != type2)
00635                 {
00636                         lck_policy.assignment_lock_policy(type1);
00637                         const bool src_policy_eq_this = (this == &src_policy);
00638                         release(type1, clone_fct1, lck_policy);
00639                         type1 = type2;
00640                         clone_fct1 = clone_fct2;
00641                         if (type1 && !src_policy_eq_this) intrusive_ptr_add_ref(type1);
00642                 }
00643         }
00644 };
00645 
00653 struct no_lock_policy
00654 {
00655         no_lock_policy(){}
00656         template<class T_obj> inline void pointee_lock_policy(T_obj*){}
00657         template<class T_obj> inline void const_pointee_lock_policy(T_obj*){}
00658         template<class T_obj> inline void assignment_lock_policy(T_obj*){}
00659         template<class T_obj> inline void assignment_unlock_policy(T_obj*){}
00660         template<class T_obj> inline void destructor_lock_policy(T_obj*){}
00661         template<class T_obj> inline void destructor_unlock_policy(T_obj*){}
00662         template<class T_obj> inline T_obj* constructor_lock_policy(T_obj* p){return p;}
00663         template<class T_obj> inline void constructor_unlock_policy(T_obj*){}
00664         // @cond INCLUDE_ALL_OBJS_
00665         template<class T> struct return_type{typedef T* type_pointee;typedef T& type_ref;};//The struct type is here for a future optional feature
00666         // @endcond
00667         //A lock policy should have the following two functions implemented
00668         template<class T_obj> inline void lock(T_obj*){}
00669         template<class T_obj> inline void unlock(T_obj*){}
00670 private:
00671         //A lock policy can optionally have the following two functions implemented and public
00672         template<class T_obj> inline bool trylock(T_obj*);
00673         template<class T_obj> inline bool islock(T_obj*);// Should only be used with trylock
00674         //The following should always be private with non implementation
00675         no_lock_policy(const no_lock_policy&);
00676         no_lock_policy& operator=(const no_lock_policy&);
00677 };
00678 
00704 struct intrusive_lock_policy
00705 {
00706         intrusive_lock_policy(){}
00707         template<class T_obj> inline void pointee_lock_policy(T_obj* p){}
00708         template<class T_obj> inline void const_pointee_lock_policy(T_obj* p){}
00709         template<class T_obj> inline void assignment_lock_policy(T_obj* p){if (p) lock(p);}
00710         template<class T_obj> inline void assignment_unlock_policy(T_obj* p){if (p) unlock(p);}
00711         template<class T_obj> inline void destructor_lock_policy(T_obj* p){if (p) lock(p);}
00712         template<class T_obj> inline void destructor_unlock_policy(T_obj* p){if (p) unlock(p);}
00713         template<class T_obj> inline T_obj* constructor_lock_policy(T_obj* p){if (p) lock(p);return p;}
00714         template<class T_obj> inline void constructor_unlock_policy(T_obj* p){if (p) unlock(p);}
00715         template<class T_obj> inline void lock(T_obj* p){intrusive_ptr_lock(p);}
00716         template<class T_obj> inline void unlock(T_obj* p){intrusive_ptr_unlock(p);}
00717         template<class T_obj> inline bool trylock(T_obj* p){return intrusive_ptr_trylock(p);}
00718         template<class T_obj> inline bool islock(T_obj* p){return intrusive_ptr_islock(p);}// Should only be used with trylock
00719         // @cond INCLUDE_ALL_OBJS_
00720         template<class T> struct return_type{typedef T* type_pointee;typedef T& type_ref;};//The struct type is here for a future optional feature
00721         // @endcond
00722 private: //The following should always be private with no implementation
00723         intrusive_lock_policy(const intrusive_lock_policy&);
00724         intrusive_lock_policy& operator=(const intrusive_lock_policy&);
00725 };
00726 
00727 //See Note#2 listed below
00728 #ifndef SMART_PTR_EXCLUDE_DEFAULT_POLICY_SPECIFICATIONS_
00729 typedef no_lock_policy                                                                                          lock_default_policy;
00730 typedef ref_link_policy                                                                                         ref_default_policy;
00731 #endif // not SMART_PTR_EXCLUDE_DEFAULT_POLICY_SPECIFICATIONS_
00732 
00733 //weak_storage implementation is still in progress
00734 struct weak_storage
00735 {
00736         struct ref_count
00737         {
00738                 ref_count():m_count(new size_t(1)){}
00739                 size_t *m_count;
00740         private:  //Disallow copy constructor and assignment op
00741                 ref_count(const ref_count&);
00742                 ref_count& operator=(const ref_count&);
00743         };
00744         ref_count m_ref_count;
00745 };
00746 
00747 struct no_weak_support{};
00748 
00774 template<class REFERENCE_POLICY = ref_default_policy, class LOCK_POLICY = lock_default_policy, class WEAK_SUPPORT_POLICY = no_weak_support>
00775 class copy_on_write_policy : public REFERENCE_POLICY, public LOCK_POLICY
00776 {
00777 public:
00778         copy_on_write_policy(){}
00779         template<class T1, class F1, class T2>
00780                 inline copy_on_write_policy(REFERENCE_POLICY& src, const T1& type, const F1&, const T2&):REFERENCE_POLICY(src, type)
00781         {
00782         }
00783         template<class T, class F>
00784                 T get_non_constant_ptr(T& type, F clone_fct)
00785         {
00786                 if (REFERENCE_POLICY::is_referenced(type) && type && clone_fct)
00787                 {
00788                         assign(type, clone_fct, 
00789                                 clone_fct(type, true, NULL, NULL, NULL), 
00790                                 clone_fct, *this, *this);
00791                 }
00792                 return type;
00793         }
00794 };
00795 
00826 template<class REFERENCE_POLICY = ref_default_policy, class LOCK_POLICY = lock_default_policy, class WEAK_SUPPORT_POLICY = no_weak_support>
00827 class shared_ptr_policy : public REFERENCE_POLICY, public LOCK_POLICY
00828 {
00829 public:
00830         shared_ptr_policy(){}
00831         template<class T1, class F1, class T2>
00832                 inline shared_ptr_policy(REFERENCE_POLICY& src, const T1& type, const F1&, const T2&):REFERENCE_POLICY(src, type)
00833         {
00834         }
00835         template<class T, class F>
00836                 inline T& get_non_constant_ptr(T& type, const F&){return type;}
00837 };
00838 
00855 template<class LOCK_POLICY = lock_default_policy>
00856 class deep_copy_policy : public LOCK_POLICY
00857 {
00858 public:
00859         deep_copy_policy(){}
00860         template<class T1, class F1, class T2>
00861                 inline deep_copy_policy(deep_copy_policy&, T1 type_src, F1 clone_fct, T2& type_target)
00862         {
00863                 type_target = clone_fct(type_src, true, NULL, NULL, NULL);
00864         }
00865         template<class T, class F, class LCK>
00866                 inline void release(T& type, F clone_fct, LCK &)
00867         {
00868                 if (type && clone_fct)
00869                 {
00870                         clone_fct(type, false, NULL, NULL, NULL);
00871                 }
00872                 type = NULL;
00873         }
00874         template<class T1, class F1, class T2, class F2, class LCK>
00875                 void assign(T1& type1, F1& clone_fct1, T2 type2, const F2 clone_fct2, deep_copy_policy&, LCK &lck_policy)
00876         {
00877                 if (!type1 && type1 != type2)
00878                 {
00879                         lck_policy.assignment_lock_policy(type1);
00880                         release(type1, clone_fct1, lck_policy);
00881                         if (type2)
00882                                 type1 = clone_fct2(type2, true, NULL, NULL, NULL);
00883                         clone_fct1 = clone_fct2;
00884                 }
00885         }
00886         template<class T, class F>
00887                 inline T& get_non_constant_ptr(T& type, const F&)
00888         {//deep copy policy always clones on the constructor, so no need to clone here, and we can just return the pointer
00889                 return type;
00890         }
00891 };
00892 
00897 struct no_checking_policy
00898 {
00899         template<class T_obj> static void check_type_pass_to_constructor(T_obj*){}
00900         template<class T_obj> static void on_dereference(T_obj*){}
00901         template<class T_obj> static void on_const_dereference(T_obj*){}
00902         template<class T_obj> static void before_release(T_obj*){}
00903         template<class T_obj> static void after_release(T_obj*){}
00904 };
00905 
00906 // @cond INCLUDE_ALL_OBJS_
00907 struct boost_assert_checking_policy
00908 {
00909 #ifdef BOOST_ASSERT
00910         template<class T_obj> static void check_type_pass_to_constructor(T_obj*){}
00911         template<class T_obj> static void on_dereference(T_obj*){}
00912         template<class T_obj> static void on_const_dereference(T_obj*){}
00913 #else
00914         template<class T_obj> static void check_type_pass_to_constructor(T_obj* type)
00915         {
00916                 BOOST_ASSERT(type != NULL);
00917                 BOOST_ASSERT(typeid(*type) == typeid(T_obj));
00918         }
00919         template<class T_obj> static void on_dereference(T_obj* type)
00920         {
00921                 BOOST_ASSERT(type != NULL);
00922                 BOOST_ASSERT(typeid(*type) == typeid(T_obj));
00923         }
00924         template<class T_obj> static void on_const_dereference(T_obj* type)
00925         {
00926                 BOOST_ASSERT(type != NULL);
00927                 BOOST_ASSERT(typeid(*type) == typeid(T_obj));
00928         }
00929 #endif //BOOST_ASSERT
00930         template<class T_obj> static void before_release(T_obj*){}
00931         template<class T_obj> static void after_release(T_obj*){}
00932 };
00933 // @endcond 
00934 
00935 
00944 #if defined(_MSC_VER) && (_MSC_VER <= 1200)
00945 template < typename TT, typename DT, typename AL> TT * constructor_and_destructor_allocator_function( TT *  ptr, bool bConstruct, DT*, AL* , void*) //Seen Note#1 below, for details on the last three arguments
00946 {// The clone function method: (Thanks to Kai-Uwe Bux)
00947         if (!ptr) return NULL;
00948         if (bConstruct){return AL::allocate(static_cast<const DT*>(ptr));}
00949         AL::deallocate(ptr);
00950         return NULL;
00951 }
00952 #endif //defined(_MSC_VER) && (_MSC_VER <= 1200)
00953 
00954 
00968 #ifndef SMART_PTR_EXCLUDE_DEFAULT_POLICY_SPECIFICATIONS_
00969 typedef value_comparsion_semantic_policy                                                                comparison_default_policy;
00970 typedef no_stream_operator_semantic_policy                                                              stream_default_policy;
00971 typedef no_checking_policy                                                                                              checking_default_policy;
00972 //The following two default policies are declared above the ownership polices
00973 //typedef no_lock_policy                                                                                                lock_default_policy;
00974 //typedef ref_link_policy                                                                                               ref_default_policy;
00975 typedef copy_on_write_policy<ref_default_policy, lock_default_policy>   ownership_default_policy;
00976 typedef no_arithmetic_semantic_policy                                                                   arithmetic_default_policy;
00977 #endif // not SMART_PTR_EXCLUDE_DEFAULT_POLICY_SPECIFICATIONS_
00978 
00992 template<class T, class ALLOCATOR_POLICY>
00993 class smart_ptr_base
00994 {
00995 protected:
00996         typedef T * ( *clone_fct_Type ) (const T *, bool, void*, ALLOCATOR_POLICY*, void*);//Last two values are not used (See note#1 at end of file)
00997         T* m_type;
00998         clone_fct_Type m_clone_fct;
00999         inline smart_ptr_base(T* type, clone_fct_Type clone_fct): m_type(type), m_clone_fct(clone_fct){}
01000         inline ~smart_ptr_base() throw()
01001         {
01002                 if (m_type) m_clone_fct(m_type, false, NULL, NULL, NULL);
01003         }
01004 private:
01005         smart_ptr_base(const smart_ptr_base&);
01006         smart_ptr_base& operator=(const smart_ptr_base& Src);
01007 };
01008 
01009 
01140 //----------------------------------------------------------------------------------------
01141 //----------------------------------------------------------------------------------------
01142 //----------------------------------------------------------------------------------------
01143 //----------------------------------------------------------------------------------------
01144 //Start of smart_ptr class
01145 
01146 template<class T, 
01147         //Available OWNERSHIP_POLICY policies:                          shared_ptr_policy<ref_link_policy>, copy_on_write_policy<ref_link_policy>, deep_copy_policy, shared_ptr_policy<ref_count_policy>, copy_on_write_policy<ref_count_policy>, shared_ptr_policy<ref_intrusive_policy>, copy_on_write_policy<ref_intrusive_policy>
01148         class OWNERSHIP_POLICY = ownership_default_policy , 
01149         //Available ALLOCATOR_POLICY policies:                          allocator_default_policy, clone_function_allocator_policy, clone_static_function_allocator_policy
01150         class ALLOCATOR_POLICY =  allocator_default_policy,
01151         //Available CHECKING_POLICY policies:                           no_checking_policy, boost_assert_checking_policy
01152         class CHECKING_POLICY =  checking_default_policy,
01153         //Available COMPARISON_SEMANTIC_POLICY policies:        value_comparsion_semantic_policy, pointer_comparsion_semantic_policy, no_comparsion_semantic_policy 
01154         class COMPARISON_SEMANTIC_POLICY = comparison_default_policy,
01155         //Available STREAM_OP_SEMANTIC_POLICY policies:         value_stream_operator_semantic_policy, no_stream_operator_semantic_policy  (Not supported on VC++6.0)
01156         class STREAM_OP_SEMANTIC_POLICY = stream_default_policy,
01157         //Available ARITHMETIC_SEMANTIC_POLICY policies:        no_arithmetic_semantic_policy, value_arithmetic_semantic_policy  (Not support for non-compliant compilers like VC++6.0 and BCC55)
01158         class ARITHMETIC_SEMANTIC_POLICY = arithmetic_default_policy>
01159 class smart_ptr : smart_ptr_base<T, ALLOCATOR_POLICY>
01160 {
01161         enum implement_default_object{eYes, eNo};
01162         mutable OWNERSHIP_POLICY m_ownership_policy;
01163 public:
01169         template<typename T_obj>
01170                 inline smart_ptr(T_obj* type):smart_ptr_base<T,ALLOCATOR_POLICY>(type, get_alloc_func(type))
01171         {
01172                 CHECKING_POLICY::check_type_pass_to_constructor(type);
01173         }
01175         inline smart_ptr(const smart_ptr& Src):smart_ptr_base<T,ALLOCATOR_POLICY>(Src.m_ownership_policy.constructor_lock_policy(Src.m_type), Src.m_clone_fct), m_ownership_policy(Src.m_ownership_policy, Src.m_type, Src.m_clone_fct, m_type){Src.m_ownership_policy.constructor_unlock_policy(Src.m_type);}
01177         smart_ptr(implement_default_object use_default_obj = eYes):smart_ptr_base<T,ALLOCATOR_POLICY>(NULL, NULL)
01178         {
01179                 if (use_default_obj == eYes)
01180                 {
01181                         smart_ptr& default_obj = get_or_set_default_object();
01182                         default_obj.lock();
01183                         m_ownership_policy.assign(m_type, m_clone_fct, default_obj.m_type, default_obj.m_clone_fct, default_obj.m_ownership_policy, m_ownership_policy);
01184                         default_obj.unlock();
01185                 }
01186         }
01188         inline ~smart_ptr() throw()
01189         {
01190                 m_ownership_policy.destructor_lock_policy(m_type);
01191                 CHECKING_POLICY::before_release(m_type);
01192                 m_ownership_policy.release(m_type, m_clone_fct, m_ownership_policy);
01193                 CHECKING_POLICY::after_release(m_type);
01194                 m_type = NULL;
01195         }
01196 #if !defined(_MSC_VER) || (_MSC_VER > 1200)
01197 
01198         template<class CompatibleDerivedT,      class OWNERSHIP_POLICY_T,       class ALLOCATOR_POLICY_T,       class CHECKING_POLICY_T,        class COMPARISON_SEMANTIC_POLICY_T,     class STREAM_OPERATOR_SEMANTIC_POLICY_T,        class ARITHMETIC_SEMANTIC_POLICY_T>
01199                 smart_ptr(const smart_ptr<CompatibleDerivedT, OWNERSHIP_POLICY_T, ALLOCATOR_POLICY_T, CHECKING_POLICY_T, COMPARISON_SEMANTIC_POLICY_T, STREAM_OPERATOR_SEMANTIC_POLICY_T, ARITHMETIC_SEMANTIC_POLICY_T>& Src):smart_ptr_base<T,ALLOCATOR_POLICY>(NULL, NULL)
01200         {//No clean way to do this, so just clone it
01201                 Src.lock();
01202                 Src.make_clone(m_type, m_clone_fct);
01203                 Src.unlock();
01204         }
01206 
01208         template<class CompatibleDerivedT,      class OWNERSHIP_POLICY_T,       class ALLOCATOR_POLICY_T,       class CHECKING_POLICY_T,        class COMPARISON_SEMANTIC_POLICY_T, class STREAM_OPERATOR_SEMANTIC_POLICY_T,    class ARITHMETIC_SEMANTIC_POLICY_T>
01209                 smart_ptr& operator=(const smart_ptr<CompatibleDerivedT, OWNERSHIP_POLICY_T, ALLOCATOR_POLICY_T, CHECKING_POLICY_T, COMPARISON_SEMANTIC_POLICY_T, STREAM_OPERATOR_SEMANTIC_POLICY_T, ARITHMETIC_SEMANTIC_POLICY_T>& Src)
01210         {//No clean way to do this, so just clone it
01211                 if (m_type != Src.c_ptr())
01212                 {
01213                         m_ownership_policy.assignment_lock_policy(m_type);
01214                         CHECKING_POLICY::before_release(m_type);
01215                         m_ownership_policy.release(m_type, m_clone_fct, m_ownership_policy);
01216                         CHECKING_POLICY::after_release(m_type);
01217                         Src.lock();
01218                         Src.make_clone(m_type, m_clone_fct);
01219                         Src.unlock();
01220                 }
01221                 return *this;
01222         }
01223 #else
01224         //For VC++6.0 the smart_ptr is only interchangeable through assignment operator
01225         template<class CompatiblePointerTypeForVC60>
01226         smart_ptr& operator=(const CompatiblePointerTypeForVC60& Src)
01227         {//No clean way to do this, so just clone it
01228                 m_ownership_policy.assignment_lock_policy(m_type);
01229                 CHECKING_POLICY::before_release(m_type);
01230                 m_ownership_policy.release(m_type, m_clone_fct, m_ownership_policy);
01231                 if (m_type) m_ownership_policy.assignment_unlock_policy(m_type);
01232                 CHECKING_POLICY::after_release(m_type);
01233                 Src.lock();
01234                 Src.make_clone(m_type, m_clone_fct);
01235                 Src.unlock();
01236                 return *this;
01237         }
01238 #endif //_MSC_VER noteq 1200
01239 
01240         smart_ptr& operator=(smart_ptr& Src)
01241         {
01242                 if (m_type != Src.m_type)
01243                 {
01244                         Src.lock();
01245                         m_ownership_policy.assign(m_type, m_clone_fct, Src.m_type, Src.m_clone_fct, Src.m_ownership_policy, m_ownership_policy);
01246                         Src.unlock();
01247                 }
01248                 return *this;
01249         }
01250         bool operator! () const{return c_ptr() == 0;}
01251 #ifdef SMART_PTR_SUPPORT_RETURN_TYPE_THROUGH_POLICY_
01252         // @cond INCLUDE_ALL_OBJS_
01253         //Return type for arithmetic operators
01254         typedef typename ARITHMETIC_SEMANTIC_POLICY::template return_type<smart_ptr>::type arith_retrn_type;
01255         // @endcond 
01256         //The arithmetic semantic policy might not make it through boost peer review, so for now there's only
01257         //a limited set for demonstration purposes.
01258         arith_retrn_type& operator+=(const smart_ptr& Src){return ARITHMETIC_SEMANTIC_POLICY::plus_equal_smart_ptr(*this, Src);}
01259         template<class T2>      arith_retrn_type& operator+=(const T2& Src){return ARITHMETIC_SEMANTIC_POLICY::plus_equal(*this, Src);}
01260         arith_retrn_type& operator-=(const smart_ptr& Src){return ARITHMETIC_SEMANTIC_POLICY::minus_equal_smart_ptr(*this, Src);}
01261         template<class T2>      arith_retrn_type& operator-=(const T2& Src){return ARITHMETIC_SEMANTIC_POLICY::minus_equal(*this, Src);}
01262         friend arith_retrn_type operator+(const smart_ptr& a, const smart_ptr& b){return ARITHMETIC_SEMANTIC_POLICY::plus(a, b);}
01263         friend arith_retrn_type operator-(const smart_ptr& a, const smart_ptr& b){return ARITHMETIC_SEMANTIC_POLICY::minus(a, b);}
01264         //
01265         // @cond INCLUDE_ALL_OBJS_
01266         typedef typename OWNERSHIP_POLICY::template return_type<T>::type_pointee ownership_retrn_type_pointee;
01267         typedef typename OWNERSHIP_POLICY::template return_type<T>::type_ref ownership_retrn_type_ref;
01268         // @endcond 
01269         //Operators that will force exclusive pointer
01270         inline ownership_retrn_type_pointee operator->() 
01271         {
01272                 m_ownership_policy.pointee_lock_policy(m_type);
01273                 CHECKING_POLICY::on_dereference(m_type);
01274                 return m_ownership_policy.get_non_constant_ptr(m_type, m_clone_fct);
01275         }
01276         inline ownership_retrn_type_ref operator*() 
01277         {
01278                 m_ownership_policy.pointee_lock_policy(m_type);
01279                 CHECKING_POLICY::on_dereference(m_type);
01280                 return *m_ownership_policy.get_non_constant_ptr(m_type, m_clone_fct);
01281         }
01282         inline ownership_retrn_type_pointee operator->()const {
01283                 m_ownership_policy.const_pointee_lock_policy(m_type);
01284                 CHECKING_POLICY::on_const_dereference(m_type);
01285                 return m_type;
01286         }
01287         inline ownership_retrn_type_ref operator*() const {
01288                 m_ownership_policy.const_pointee_lock_policy(m_type);
01289                 CHECKING_POLICY::on_const_dereference(m_type);
01290                 return *m_type;
01291         }
01292 #else
01293         //Operators that will force exclusive pointer
01294         inline T* operator->() 
01295         {
01296                 m_ownership_policy.pointee_lock_policy(m_type);
01297                 CHECKING_POLICY::on_dereference(m_type);
01298                 return m_ownership_policy.get_non_constant_ptr(m_type, m_clone_fct);
01299         }
01300         inline T& operator*() 
01301         {
01302                 m_ownership_policy.pointee_lock_policy(m_type);
01303                 CHECKING_POLICY::on_dereference(m_type);
01304                 return *m_ownership_policy.get_non_constant_ptr(m_type, m_clone_fct);
01305         }
01306         inline const T* operator->()const {
01307                 m_ownership_policy.const_pointee_lock_policy(m_type);
01308                 CHECKING_POLICY::on_const_dereference(m_type);
01309                 return m_type;
01310         }
01311         inline const T& operator*() const {
01312                 m_ownership_policy.const_pointee_lock_policy(m_type);
01313                 CHECKING_POLICY::on_const_dereference(m_type);
01314                 return *m_type;
01315         }
01316 #endif //SMART_PTR_SUPPORT_RETURN_TYPE_THROUGH_POLICY_
01317 
01318 
01324         void lock() const {if (m_type) m_ownership_policy.lock(m_type);}
01328         void unlock() const {if (m_type) m_ownership_policy.unlock(m_type);}
01333         void trylock() const {if (m_type) m_ownership_policy.trylock(m_type);}
01339         void islock() const {if (m_type) m_ownership_policy.islock(m_type);}// Should only be used with trylock
01341 
01342 
01348         static void set_default_object(const smart_ptr& NewValue){get_or_set_default_object(&NewValue);}
01353         template<class T2>      smart_ptr& equal(const T2& Src){
01354                 (*get_ptr()) = (Src);
01355                 return *this;
01356         }
01360         clone_fct_Type get_function_ptr()const{return m_clone_fct;}
01364         void swap(smart_ptr<T> & other)throw(){std::swap(m_ownership_policy, other.m_ownership_policy);std::swap(m_type, other.m_type);std::swap(m_clone_fct, other.m_clone_fct);}
01370         template<class PT, class FPT>   void make_clone(PT*& ptr, FPT& func_ptr) const
01371         {
01372                 if (m_type && m_clone_fct)
01373                 {
01374                         ptr = m_clone_fct(m_type, true, NULL, NULL, NULL);
01375                         func_ptr = (FPT)m_clone_fct;
01376                 }
01377                 else
01378                         ptr = NULL;
01379         }
01381 
01382 
01385         inline T* get_ptr(){return m_ownership_policy.get_non_constant_ptr(m_type, m_clone_fct);}
01386         inline const T* c_ptr()const{return  m_type;}
01387         inline const T& c_ref()const{return  *m_type;}
01389 
01390         // @cond INCLUDE_ALL_OBJS_
01391         typedef COMPARISON_SEMANTIC_POLICY comparison_semantic_policy_type;
01392         typedef T* pointer;
01393         typedef T& reference;
01394         // @endcond 
01395 private:
01396 #if !defined(_MSC_VER) || (_MSC_VER > 1200)
01397 /*
01398 Note#1:
01399 The constructor_and_destructor_allocator_function function has three extra arguments that are not used.  These arguments are not required at all in more compliant compilers
01400 like VC++ 7.x and GNU 3.x.  However, for none compliant (pre-standard) compilers like VC++ 6.0 and BCC55, the extra argument declaration is required
01401 so as to be able to fully qualify the function template type.  The argument declarations are needed for these compilers, but the actual argument variables
01402 are not needed.  Anything pass to these last three arguments is discarded.
01403 */
01404         template < typename TT, typename DT, typename AL> static TT * constructor_and_destructor_allocator_function( TT *  ptr, bool bConstruct, DT*, AL* , void*) 
01405         {
01406                 if (!ptr) return NULL;
01407                 if (bConstruct){return AL::allocate(static_cast<const DT*>(ptr));}
01408                 AL::deallocate(ptr);
01409                 return NULL;
01410         } 
01411         template<typename T_obj>
01412                 inline static   clone_fct_Type get_alloc_func(T_obj*)
01413         {
01414                 T * ( *tmp ) (T *, bool, T_obj*, ALLOCATOR_POLICY*, void*) = constructor_and_destructor_allocator_function<T,T_obj,ALLOCATOR_POLICY>;
01415                 return (clone_fct_Type)tmp;
01416         }
01417 #else
01418         template<typename T_obj>
01419                 inline static   clone_fct_Type get_alloc_func(T_obj*)
01420         {
01421                 T * ( *tmp ) (T *, bool, T_obj*, ALLOCATOR_POLICY*, void*) = constructor_and_destructor_allocator_function<T,T_obj,ALLOCATOR_POLICY>;
01422                 if (!tmp) constructor_and_destructor_allocator_function((T*)NULL, false, (T_obj*)NULL, (ALLOCATOR_POLICY*)NULL, NULL);
01423                 return (clone_fct_Type)tmp;
01424         }
01425 #endif //_MSC_VER noteq 1200
01426 
01427         static smart_ptr& get_or_set_default_object(const smart_ptr* NewValue = NULL)
01428         {
01429                 static smart_ptr DefaultObj(eNo);
01430                 if (NewValue && NewValue->m_type)
01431                         DefaultObj = *NewValue;
01432                 return DefaultObj;
01433         }
01434 
01435 #if !defined(_MSC_VER) || (_MSC_VER > 1200)
01436         template<class T1> friend bool operator==(const smart_ptr & a, const T1 & b){return T1::comparison_semantic_policy_type::is_equal(a,b);}
01437         template<class T1> friend bool operator!=(const smart_ptr & a, const T1 & b){return !T1::comparison_semantic_policy_type::is_equal(a,b);}
01438         template<class T1> friend bool operator> (const smart_ptr & a, const T1 & b){return T1::comparison_semantic_policy_type::greater_than(a,b);}
01439         template<class T1> friend bool operator< (const smart_ptr & a, const T1 & b){return T1::comparison_semantic_policy_type::less_than(a,b);}
01440         template<class T1> friend bool operator>=(const smart_ptr & a, const T1 & b){return T1::comparison_semantic_policy_type::greater_than_or_equal(a,b);}
01441         template<class T1> friend bool operator<=(const smart_ptr & a, const T1 & b){return T1::comparison_semantic_policy_type::less_than_or_equal(a,b);}
01442 #else //Can not support exchangeable comparison in VC++ 6.0 
01443         friend inline bool operator==(const smart_ptr & a, const smart_ptr & b){return COMPARISON_SEMANTIC_POLICY::is_equal(a,b);}
01444         friend inline bool operator!=(const smart_ptr & a, const smart_ptr & b){return !COMPARISON_SEMANTIC_POLICY::is_equal(a,b);}
01445         friend inline bool operator< (const smart_ptr & a, const smart_ptr & b){return COMPARISON_SEMANTIC_POLICY::less_than(a,b);}
01446         friend inline bool operator> (const smart_ptr & a, const smart_ptr & b){return COMPARISON_SEMANTIC_POLICY::greater_than(a,b);}
01447         friend inline bool operator<=(const smart_ptr & a, const smart_ptr & b){return COMPARISON_SEMANTIC_POLICY::less_than_or_equal(a,b);}
01448         friend inline bool operator>=(const smart_ptr & a, const smart_ptr & b){return COMPARISON_SEMANTIC_POLICY::greater_than_or_equal(a,b);}
01449 #endif //not defined(_MSC_VER) || (_MSC_VER > 1200)
01450 
01451 #if __GNUC__ == 2 && __GNUC_MINOR__ <= 96
01452 // Resolve the ambiguity between our op!= and the one in rel_ops
01453         template<class T> friend bool operator!=(const smart_ptr<T> & a, const smart_ptr<T> & b){return !COMPARISON_SEMANTIC_POLICY::is_equal(a,b);}
01454 #endif
01455 
01456         template<class T1> T1& input_stream(T1 &is){return STREAM_OP_SEMANTIC_POLICY::input_stream(is, *this);}
01457         template<class T1> T1& output_stream(T1 &io) const {return STREAM_OP_SEMANTIC_POLICY::output_stream(io, *this);}
01458 
01459         template<class TS> inline friend TS& operator >>(TS &is,smart_ptr &obj){return obj.input_stream(is);}
01460         template<class TS> inline friend TS& operator <<(TS &io,const smart_ptr &obj){return obj.output_stream(io);}
01461 
01462 };
01463 
01464 // @cond INCLUDE_ALL_OBJS_
01465 
01466 //The following smart_ptr_type, allows typedef declarations for certain types
01467 //Example:
01468 //typedef smart_ptr_type<copy_on_write_policy<ref_link_policy, intrusive_lock_policy> > MyCowSyncSmartPtr;
01469 //MyCowSyncSmartPtr::to<Shape>::type pShape1;
01470 template< 
01471 //Available OWNERSHIP_POLICY policies:                          shared_ptr_policy<ref_link_policy>, copy_on_write_policy<ref_link_policy>, deep_copy_policy, shared_ptr_policy<ref_count_policy>, copy_on_write_policy<ref_count_policy>, shared_ptr_policy<ref_intrusive_policy>, copy_on_write_policy<ref_intrusive_policy>
01472 class OWNERSHIP_POLICY = ownership_default_policy , 
01473         //Available ALLOCATOR_POLICY policies:                          allocator_default_policy, clone_function_allocator_policy, clone_static_function_allocator_policy
01474 class ALLOCATOR_POLICY =  allocator_default_policy,
01475         //Available CHECKING_POLICY policies:                           no_checking_policy, boost_assert_checking_policy
01476 class CHECKING_POLICY =  checking_default_policy,
01477         //Available COMPARISON_SEMANTIC_POLICY policies:        value_comparsion_semantic_policy, pointer_comparsion_semantic_policy, no_comparsion_semantic_policy 
01478 class COMPARISON_SEMANTIC_POLICY = comparison_default_policy,
01479         //Available STREAM_OP_SEMANTIC_POLICY policies:         value_stream_operator_semantic_policy, no_stream_operator_semantic_policy  (Not supported on VC++6.0)
01480 class STREAM_OP_SEMANTIC_POLICY = stream_default_policy,
01481         //Available ARITHMETIC_SEMANTIC_POLICY policies:        no_arithmetic_semantic_policy, value_arithmetic_semantic_policy  (Not support for non-compliant compilers like VC++6.0 and BCC55)
01482 class ARITHMETIC_SEMANTIC_POLICY = arithmetic_default_policy>
01483 struct smart_ptr_type
01484 {//Future version of this class will have struct 'to' removed, and ptr_to, might get renamed to 'to'
01485         template<class T> struct to{typedef smart_ptr<T, OWNERSHIP_POLICY, ALLOCATOR_POLICY, CHECKING_POLICY, COMPARISON_SEMANTIC_POLICY, STREAM_OP_SEMANTIC_POLICY, ARITHMETIC_SEMANTIC_POLICY> type;};
01486         template<class T> struct ptr_to : public smart_ptr<T, OWNERSHIP_POLICY, ALLOCATOR_POLICY, CHECKING_POLICY, COMPARISON_SEMANTIC_POLICY, STREAM_OP_SEMANTIC_POLICY, ARITHMETIC_SEMANTIC_POLICY>{};
01487         template<class T1> inline smart_ptr_type(T1 &t1): smart_ptr(t1){}
01488 };
01489 
01490 
01491 struct smart_ptr_policies  //Common policies
01492 {
01493         typedef smart_ptr_type<copy_on_write_policy<ref_link_policy, intrusive_lock_policy> >   cow_sync_ptr; 
01494         typedef smart_ptr_type<deep_copy_policy<intrusive_lock_policy> >                                                copy_sync_ptr; 
01495         typedef smart_ptr_type<shared_ptr_policy<ref_link_policy, intrusive_lock_policy> >              shared_sync_ptr; 
01496         typedef smart_ptr_type<copy_on_write_policy<ref_link_policy> >                                                  cow_ptr; 
01497         typedef smart_ptr_type<deep_copy_policy<> >                                                                                             copy_ptr; 
01498         typedef smart_ptr_type<shared_ptr_policy<ref_link_policy> >                                                             shared_ptr; 
01499 };
01500 // @endcond 
01501 
01556 #endif //not smart_ptr_HPP_HEADER_GUARD_
01557 

Generated on Wed Mar 29 21:58:58 2006 for Smart Pointers by  doxygen 1.4.6.Axter [Axter-Extended-Version]