My Project
cow_ptr.hpp
1 #ifndef cow_ptr_H_HEADER_GUARD_
2 #define cow_ptr_H_HEADER_GUARD_
3 
4 /*
5 // cow_ptr class by David Maisonave (Axter)
6 // Copyright (C) 2005
7 // David Maisonave (Axter) (609-345-1007) (www.axter.com)
8 //
9 // Permission to use, copy, modify, distribute and sell this software
10 // and its documentation for any purpose is hereby granted without fee,
11 // provided that the above copyright notice appear in all copies and
12 // that both that copyright notice and this permission notice appear
13 // in supporting documentation. David Maisonave (Axter) makes no representations
14 // about the suitability of this software for any purpose.
15 // It is provided "as is" without express or implied warranty.
16 Description: COW = Copy On Write
17 The cow_ptr class is a smart pointer class that can be used
18 with an STL container to create a container of smart pointers.
19 The main purpose of the cow_ptr, is to make it easier to create
20 a container of abstract based objects with a smart pointer that has
21 lazy construction logic.
22 The cow_ptr will share the pointer until one of the shared objects tries
23 to access the non-constant pointer. At that point, the object is cloned,
24 and it releases the reference count to the original pointer.
25 The main difference between cow_ptr and other similar smart pointers
26 is that the cow_ptr has a clone function pointer, which is used to create
27 a copy of the derived object. The clone function pointer is used in
28 the cow_ptr copy constructor and in the assignment operator.
29 
30 The cow_ptr can also be used with sorted containers (std::map, std::set).
31 When used with sorted containers, the base class must have an operator<() function. (See example code.)
32 
33 ****** For more detailed description and example usage see following links: *******
34 Example Program:
35 http://code.axter.com/clone_ptr_demo.zip
36 
37 See example program for example usage.
38 
39 cow_ptr<std::string> test_ptr1(new std::string("some value"));
40 cow_ptr<std::string> test_ptr2 = test_ptr1;
41 std::string readonly_op = test_ptr2.c_ref().c_str();
42 (*test_ptr2) = "some value2";
43 
44 */
45 
46 #include <algorithm>
47 
48 // The clone function: (Thanks to Kai-Uwe Bux)
49 template < typename T, typename DT> T * cow_ptr_ConstructAndDestruct_default_allocator_(T*, bool, DT* , void*);
50 
55 template<typename T>
56 class cow_ptr
57 {
58  typedef T * ( *clone_fct_Type ) (const T *, bool, void*, void*);//Last two values are not used (See note#1 at end of file)
59  struct ref_link
60  {
61  ref_link():m_back(NULL), m_front(NULL){}
62  ref_link *m_back;
63  ref_link *m_front;
64  private: //Disallow copy constructor and assignment op
65  ref_link(const ref_link&);
66  ref_link& operator=(const ref_link&);
67  };
68  mutable ref_link m_ref_link;
69  T* m_type;
70  clone_fct_Type m_clone_fct;
71 public:
72  //cow_ptr will only clone type that is pass to the constructor
73  template<typename T_obj>
74  cow_ptr(T_obj* type): m_type(type), m_clone_fct(get_alloc_func(type))
75  {
76 #ifdef BOOST_ASSERT
77  BOOST_ASSERT(type != NULL);
78  BOOST_ASSERT(typeid(*type) == typeid(T_obj));
79 #endif //BOOST_ASSERT
80  }
81  //Destructor
82  ~cow_ptr() throw(){release();}
83  //Copy constructor
84  cow_ptr(const cow_ptr& Src):m_type(Src.m_type), m_clone_fct(Src.m_clone_fct){insert_link(&Src.m_ref_link);}
85 #if !defined(_MSC_VER) || (_MSC_VER > 1200)
86  //Constructor for smart pointer derived type cow_ptr<DerivedT>
87  template<class CompatibleDerivedT>
88  cow_ptr(const cow_ptr<CompatibleDerivedT>& Src):m_type(NULL), m_clone_fct(NULL)
89  {//No clean way to do this via COW, so just clone it
90  Src.make_clone(m_type, m_clone_fct);
91  }
92  template<class CompatibleDerivedT>
93  cow_ptr& operator=(const cow_ptr<CompatibleDerivedT>& Src)
94  {//No clean way to do this via COW, so just clone it
95  release();
96  Src.make_clone(m_type, m_clone_fct);
97  return *this;
98  }
99 #endif //_MSC_VER != 1200
100  //Assignment operator
101  cow_ptr& operator=(const cow_ptr& Src){return assign(Src);}
102  enum implement_default_object{eYes, eNo};
103  //Default constructor needed for std::map
104  cow_ptr(implement_default_object use_default_obj = eYes):m_type(NULL), m_clone_fct(NULL)
105  {
106  if (use_default_obj == eYes)
107  assign(GetSetDefaultObject());
108  }
109  //For added safety, call SetDefaultObject to set default object before
110  //using this class as the second type in a std::map
111  static void SetDefaultObject(const cow_ptr<T>& NewValue){GetSetDefaultObject(&NewValue);}
112  typedef T* pointer;
113  typedef T& reference;
114  bool operator! () const{return c_ptr() == 0;}
115  template<class T2>
116  cow_ptr& equal(const T2& Src){
117  (*get_ptr()) = (Src);
118  return *this;
119  }
120  //Operators that will force exclusive pointer
121  inline T* operator->() {return get_ptr();}
122  inline T& operator*() {return *get_ptr();}
123  inline const T* operator->()const {return m_type;}
124  inline const T& operator*() const {return *m_type;}
125  cow_ptr& operator+=(const cow_ptr& Src){
126  get_ptr()->operator+=(*Src.c_ptr());
127  return *this;
128  }
129  template<class T2>
130  cow_ptr& operator+=(const T2& Src){
131  get_ptr()->operator+=(Src);
132  return *this;
133  }
134  cow_ptr& operator+(const cow_ptr& Src){
135  get_ptr()->operator+(*Src.c_ptr());
136  return *this;
137  }
138  cow_ptr& operator-=(const cow_ptr& Src){
139  get_ptr()->operator-=(*Src.c_ptr());
140  return *this;
141  }
142  cow_ptr& operator-(const cow_ptr& Src){
143  get_ptr()->operator-(*Src.c_ptr());
144  return *this;
145  }
146  clone_fct_Type get_function_ptr()const{return m_clone_fct;}
147  T* get_ptr() //get exclusive pointer
148  {
149  if (is_ref_linked())
150  {
151  T* tmp = m_clone_fct(m_type, true, NULL, NULL);
152  release();
153  m_type = tmp;
154  }
155  return m_type;
156  }
157  inline const T* c_ptr()const{return m_type;}
158  inline const T& c_ref()const{return *m_type;}
159  //Other Misc methods
160  void swap(cow_ptr<T> & other)throw(){std::swap(m_ref_link, other.m_ref_link);std::swap(m_type, other.m_type);std::swap(m_clone_fct, other.m_clone_fct);}
161  //Needed for operator=(const cow_ptr<CompatibleDerivedT>&
162  bool is_ref_linked()const{return (m_ref_link.m_back || m_ref_link.m_front);}
163  //Allows cloning
164  template<class PT, class FPT> void make_clone(PT*& ptr, FPT& func_ptr) const
165  {
166  if (m_type)
167  {
168  ptr = m_clone_fct(m_type, true, NULL, NULL);
169  func_ptr = (FPT)m_clone_fct;
170  }
171  else
172  ptr = NULL;
173  }
174 private:
175  template<typename T_obj>
176  static clone_fct_Type get_alloc_func(T_obj*)
177  {
178  T * ( *tmp ) (T *, bool, T_obj*, void*) = cow_ptr_ConstructAndDestruct_default_allocator_<T,T_obj>;
179  return (clone_fct_Type)tmp;
180  }
181  void release() throw()
182  {
183  if (!is_ref_linked())
184  {
185  if(m_type != NULL)
186  {
187  m_clone_fct(m_type, false, NULL, NULL);
188  m_type = NULL;
189  }
190  }
191  else
192  {
193  pop_link();
194  }
195  }
196  void pop_link()
197  {
198  if (m_ref_link.m_back)
199  {
200  m_ref_link.m_back->m_front = m_ref_link.m_front;
201  }
202  if (m_ref_link.m_front)
203  {
204  m_ref_link.m_front->m_back = m_ref_link.m_back;
205  }
206  m_ref_link.m_front = NULL;
207  m_ref_link.m_back = NULL;
208  }
209  void insert_link(ref_link *Target)
210  {
211  m_ref_link.m_back = Target;
212  m_ref_link.m_front = Target->m_front;
213  if (m_ref_link.m_front)
214  {
215  m_ref_link.m_front->m_back = &m_ref_link;
216  }
217  if (m_ref_link.m_back)
218  {
219  m_ref_link.m_back->m_front = &m_ref_link;
220  }
221  }
222  template<class CompatibleSmartPtr>
223  cow_ptr& assign(CompatibleSmartPtr& Src)
224  {
225  if (!m_type || Src.is_ref_linked() || m_type != Src.c_ptr())
226  {
227  release();
228  m_type = Src.m_type;
229  m_clone_fct = Src.m_clone_fct;
230  insert_link(&Src.m_ref_link);
231  }
232  return *this;
233  }
234  static cow_ptr<T>& GetSetDefaultObject(const cow_ptr<T>* NewValue = NULL)
235  {
236  static cow_ptr<T> DefaultObj(eNo);
237  if (NewValue && NewValue->m_type)
238  DefaultObj = *NewValue;
239  return DefaultObj;
240  }
241 };
242 
243 //Operators that can work with the shared pointer
244 template<class T, class U> bool operator<(cow_ptr<T> const & a, cow_ptr<U> const & b){return (*a.c_ptr()) < (*b.c_ptr());}
245 template<class T, class U> bool operator>(cow_ptr<T> const & a, cow_ptr<U> const & b){return (*a.c_ptr()) > (*b.c_ptr());}
246 template<class T, class U> bool operator<=(cow_ptr<T> const & a, cow_ptr<U> const & b){return (*a.c_ptr()) <= (*b.c_ptr());}
247 template<class T, class U> bool operator>=(cow_ptr<T> const & a, cow_ptr<U> const & b){return (*a.c_ptr()) >= (*b.c_ptr());}
248 template<class T, class U> bool operator==(cow_ptr<T> const & a, cow_ptr<U> const & b){return (*a.c_ptr()) == (*b.c_ptr());}
249 template<class T, class U> bool operator!=(cow_ptr<T> const & a, cow_ptr<U> const & b){return (*a.c_ptr()) != (*b.c_ptr());}
250 
251 #if __GNUC__ == 2 && __GNUC_MINOR__ <= 96
252 // Resolve the ambiguity between our op!= and the one in rel_ops
253 template<class T> bool operator!=(cow_ptr<T> const & a, cow_ptr<T> const & b){return (*a.c_ptr()) != (*b.c_ptr());}
254 #endif
255 
256 
257 /*
258 Note#1:
259 The ConstructAndDestruct functions have two extra arguments that are not used. These arguments are not required at all in more compliant compilers
260 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
261 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
262 are not needed. Anything pass to these last two arguments will be discarded.
263 */
264 
265 // The clone function: (Thanks to Kai-Uwe Bux)
266 template < typename T, typename DT> T * cow_ptr_ConstructAndDestruct_default_allocator_(T * ptr, bool bConstruct, DT* , void*) {
267  if (bConstruct){return new DT(*static_cast<const DT*>(ptr));} //Should add assert like the following assert(typeid(*tmp_ptr) == typeid(*Obj));
268  delete const_cast<T*>(ptr); //This cast is needed for VC++ 6.0
269  return NULL;
270 }
271 
272 
273 #endif
274 
cow_ptr is a Copy On Write smart pointer. It does not require the pointee to have clone function logi...
Definition: cow_ptr.hpp:56