Panda3D
copyOnWritePointer.I
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file copyOnWritePointer.I
10  * @author drose
11  * @date 2007-04-09
12  */
13 
14 /**
15  *
16  */
17 INLINE CopyOnWritePointer::
18 CopyOnWritePointer(CopyOnWriteObject *object) :
19  _cow_object(object)
20 {
21  if (_cow_object != nullptr) {
22  _cow_object->cache_ref();
23  }
24 }
25 
26 /**
27  *
28  */
29 INLINE CopyOnWritePointer::
30 CopyOnWritePointer(const CopyOnWritePointer &copy) :
31  _cow_object(copy._cow_object)
32 {
33  if (_cow_object != nullptr) {
34  _cow_object->cache_ref();
35  }
36 }
37 
38 /**
39  *
40  */
41 INLINE void CopyOnWritePointer::
42 operator = (const CopyOnWritePointer &copy) {
43  operator = (copy._cow_object);
44 }
45 
46 /**
47  *
48  */
49 INLINE void CopyOnWritePointer::
50 operator = (CopyOnWriteObject *object) {
51  if (_cow_object != object) {
52  if (_cow_object != nullptr) {
53  cache_unref_delete(_cow_object);
54  }
55  _cow_object = object;
56  if (_cow_object != nullptr) {
57  _cow_object->cache_ref();
58  }
59  }
60 }
61 
62 /**
63  *
64  */
65 INLINE CopyOnWritePointer::
66 ~CopyOnWritePointer() {
67  if (_cow_object != nullptr) {
68  cache_unref_delete(_cow_object);
69  }
70 }
71 
72 /**
73  *
74  */
75 INLINE CopyOnWritePointer::
76 CopyOnWritePointer(CopyOnWritePointer &&from) noexcept :
77  _cow_object(from._cow_object)
78 {
79  // Steal the other's reference count.
80  from._cow_object = nullptr;
81 }
82 
83 /**
84  *
85  */
86 INLINE CopyOnWritePointer::
87 CopyOnWritePointer(PointerTo<CopyOnWriteObject> &&from) noexcept :
88  _cow_object(from.p())
89 {
90  // Steal the other's reference count, but because it is a regular pointer,
91  // we do need to include the cache reference count.
92  if (_cow_object != nullptr) {
93  _cow_object->cache_ref_only();
94  }
95  from.cheat() = nullptr;
96 }
97 
98 /**
99  *
100  */
101 INLINE void CopyOnWritePointer::
102 operator = (CopyOnWritePointer &&from) noexcept {
103  // Protect against self-move-assignment.
104  if (from._cow_object != _cow_object) {
105  CopyOnWriteObject *old_object = _cow_object;
106  _cow_object = from._cow_object;
107  from._cow_object = nullptr;
108 
109  if (old_object != nullptr) {
110  cache_unref_delete(old_object);
111  }
112  }
113 }
114 
115 /**
116  *
117  */
118 INLINE void CopyOnWritePointer::
119 operator = (PointerTo<CopyOnWriteObject> &&from) noexcept {
120  if (from.p() != _cow_object) {
121  CopyOnWriteObject *old_object = _cow_object;
122 
123  // Steal the other's reference count, but because it is a regular pointer,
124  // we do need to include the cache reference count.
125  _cow_object = from.p();
126  _cow_object->cache_ref_only();
127  from.cheat() = nullptr;
128 
129  if (old_object != nullptr) {
130  cache_unref_delete(old_object);
131  }
132  }
133 }
134 
135 /**
136  *
137  */
138 INLINE bool CopyOnWritePointer::
139 operator == (const CopyOnWritePointer &other) const {
140  return _cow_object == other._cow_object;
141 }
142 
143 /**
144  *
145  */
146 INLINE bool CopyOnWritePointer::
147 operator != (const CopyOnWritePointer &other) const {
148  return _cow_object != other._cow_object;
149 }
150 
151 /**
152  *
153  */
154 INLINE bool CopyOnWritePointer::
155 operator < (const CopyOnWritePointer &other) const {
156  return _cow_object < other._cow_object;
157 }
158 
159 #ifndef COW_THREADED
160 /**
161  * Returns a pointer locked for read. Until this pointer dereferences, calls
162  * to get_write_pointer() will force a copy.
163  *
164  * This flavor of the method is written for the non-threaded case.
165  */
167 get_read_pointer(Thread *current_thread) const {
168  return _cow_object;
169 }
170 #endif // COW_THREADED
171 
172 #ifndef COW_THREADED
173 /**
174  * Returns a pointer locked for write. If another thread or threads already
175  * hold the pointer locked for read, then this will force a copy.
176  *
177  * Until this pointer dereferences, calls to get_read_pointer() or
178  * get_write_pointer() will block.
179  *
180  * This flavor of the method is written for the non-threaded case.
181  */
184  if (_cow_object == nullptr) {
185  return nullptr;
186  }
187  if (_cow_object->get_cache_ref_count() > 1) {
188  PT(CopyOnWriteObject) new_object = _cow_object->make_cow_copy();
189  cache_unref_delete(_cow_object);
190  _cow_object = new_object;
191  _cow_object->cache_ref();
192  }
193  return _cow_object;
194 }
195 #endif // COW_THREADED
196 
197 /**
198  * Returns an unlocked pointer that you can write to. This should only be
199  * used in very narrow circumstances in which you know that no other thread
200  * may be accessing the pointer at the same time.
201  */
204  return _cow_object;
205 }
206 
207 /**
208  * Returns true if the CopyOnWritePointer contains a NULL pointer, false
209  * otherwise.
210  */
212 is_null() const {
213  return (_cow_object == nullptr);
214 }
215 
216 /**
217  * Sets the pointer to NULL.
218  */
220 clear() {
221  if (_cow_object != nullptr) {
222  cache_unref_delete(_cow_object);
223  }
224  _cow_object = nullptr;
225 }
226 
227 /**
228  * Does some easy checks to make sure that the reference count isn't
229  * completely bogus. Returns true if ok, false otherwise.
230  */
231 INLINE bool CopyOnWritePointer::
233  nassertr(_cow_object != nullptr, false);
234  return _cow_object->test_ref_count_integrity();
235 }
236 
237 /**
238  * Does some easy checks to make sure that the reference count isn't zero, or
239  * completely bogus. Returns true if ok, false otherwise.
240  */
241 INLINE bool CopyOnWritePointer::
243  nassertr(_cow_object != nullptr, false);
244  return _cow_object->test_ref_count_nonzero();
245 }
246 
247 #ifndef CPPPARSER
248 /**
249  *
250  */
251 template<class T>
253 CopyOnWritePointerTo(To *object) : CopyOnWritePointer(object) {
254 }
255 #endif // CPPPARSER
256 
257 #ifndef CPPPARSER
258 /**
259  *
260  */
261 template<class T>
264  CopyOnWritePointer(copy)
265 {
266 }
267 #endif // CPPPARSER
268 
269 #ifndef CPPPARSER
270 /**
271  *
272  */
273 template<class T>
274 INLINE void CopyOnWritePointerTo<T>::
276  CopyOnWritePointer::operator = (copy);
277 }
278 #endif // CPPPARSER
279 
280 #ifndef CPPPARSER
281 /**
282  *
283  */
284 template<class T>
285 INLINE void CopyOnWritePointerTo<T>::
286 operator = (To *object) {
287  CopyOnWritePointer::operator = (object);
288 }
289 #endif // CPPPARSER
290 
291 #ifndef CPPPARSER
292 /**
293  *
294  */
295 template<class T>
299 {
300 }
301 #endif // CPPPARSER
302 
303 #ifndef CPPPARSER
304 /**
305  *
306  */
307 template<class T>
309 CopyOnWritePointerTo(PointerTo<T> &&from) noexcept {
310  // Steal the other's reference count, but because it is a regular pointer,
311  // we do need to include the cache reference count.
312  _cow_object = from.p();
313  if (_cow_object != nullptr) {
314  _cow_object->cache_ref_only();
315  }
316  from.cheat() = nullptr;
317 }
318 #endif // CPPPARSER
319 
320 #ifndef CPPPARSER
321 /**
322  *
323  */
324 template<class T>
325 INLINE void CopyOnWritePointerTo<T>::
326 operator = (CopyOnWritePointerTo<T> &&from) noexcept {
327  CopyOnWritePointer::operator = ((CopyOnWritePointer &&)from);
328 }
329 #endif // CPPPARSER
330 
331 #ifndef CPPPARSER
332 /**
333  *
334  */
335 template<class T>
336 INLINE void CopyOnWritePointerTo<T>::
337 operator = (PointerTo<T> &&from) noexcept {
338  if (from.p() != _cow_object) {
339  CopyOnWriteObject *old_object = _cow_object;
340 
341  // Steal the other's reference count, but because it is a regular pointer,
342  // we do need to include the cache reference count.
343  _cow_object = from.p();
344  _cow_object->cache_ref_only();
345  from.cheat() = nullptr;
346 
347  if (old_object != nullptr) {
348  cache_unref_delete(old_object);
349  }
350  }
351 }
352 #endif // CPPPARSER
353 
354 #ifndef CPPPARSER
355 #ifdef COW_THREADED
356 /**
357  * See CopyOnWritePointer::get_read_pointer().
358  */
359 template<class T>
360 INLINE CPT(typename CopyOnWritePointerTo<T>::To) CopyOnWritePointerTo<T>::
361 get_read_pointer(Thread *current_thread) const {
362  // This is necessary because we don't currently have a way to cast between
363  // two compatible PointerTo types without losing the reference count.
364  CPT(typename CopyOnWritePointerTo<T>::To) to;
365  CPT(CopyOnWriteObject) from = CopyOnWritePointer::get_read_pointer(current_thread);
366  to.cheat() = (const To *)from.p();
367  from.cheat() = nullptr;
368  return to;
369 }
370 #else // COW_THREADED
371 /**
372  * See CopyOnWritePointer::get_read_pointer().
373  */
374 template<class T>
375 INLINE const typename CopyOnWritePointerTo<T>::To *CopyOnWritePointerTo<T>::
376 get_read_pointer(Thread *current_thread) const {
377  return (const To *)CopyOnWritePointer::get_read_pointer(current_thread);
378 }
379 #endif // COW_THREADED
380 #endif // CPPPARSER
381 
382 #ifndef CPPPARSER
383 #ifdef COW_THREADED
384 /**
385  * See CopyOnWritePointer::get_write_pointer().
386  */
387 template<class T>
388 INLINE PT(typename CopyOnWritePointerTo<T>::To) CopyOnWritePointerTo<T>::
390  // This is necessary because we don't currently have a way to cast between
391  // two compatible PointerTo types without losing the reference count.
392  PT(typename CopyOnWritePointerTo<T>::To) to;
394  to.cheat() = (To *)from.p();
395  from.cheat() = nullptr;
396  return to;
397 }
398 #else // COW_THREADED
399 /**
400  * See CopyOnWritePointer::get_write_pointer().
401  */
402 template<class T>
403 INLINE typename CopyOnWritePointerTo<T>::To *CopyOnWritePointerTo<T>::
406 }
407 #endif // COW_THREADED
408 #endif // CPPPARSER
409 
410 #ifndef CPPPARSER
411 /**
412  * See CopyOnWritePointer::get_unsafe_pointer().
413  */
414 template<class T>
415 INLINE typename CopyOnWritePointerTo<T>::To *CopyOnWritePointerTo<T>::
418 }
419 #endif // CPPPARSER
A template wrapper around the above class, mainly to handle the little typecasting niceties.
bool is_null() const
Returns true if the CopyOnWritePointer contains a NULL pointer, false otherwise.
void clear()
Sets the pointer to NULL.
bool test_ref_count_integrity() const
Does some easy checks to make sure that the reference count isn't completely bogus.
bool test_ref_count_nonzero() const
Does some easy checks to make sure that the reference count isn't zero, or completely bogus.
To * get_write_pointer()
See CopyOnWritePointer::get_write_pointer().
void cache_unref_delete(RefCountType *ptr)
This global helper function will unref the given ReferenceCount object, and if the reference count re...
bool test_ref_count_nonzero() const
Does some easy checks to make sure that the reference count isn't zero, or completely bogus.
void cache_ref_only() const
Decrements the cache reference count without affecting the normal reference count.
CopyOnWriteObject * get_write_pointer()
Returns a pointer locked for write.
void cache_ref() const
Explicitly increments the cache reference count and the normal reference count simultaneously.
To * get_unsafe_pointer()
See CopyOnWritePointer::get_unsafe_pointer().
bool test_ref_count_integrity() const
Does some easy checks to make sure that the reference count isn't completely bogus.
get_cache_ref_count
Returns the current reference count.
This base class provides basic reference counting, but also can be used with a CopyOnWritePointer to ...
This safely stores the primary, owned pointer to a CopyOnWriteObject.
A thread; that is, a lightweight process.
Definition: thread.h:46
const CopyOnWriteObject * get_read_pointer(Thread *current_thread) const
Returns a pointer locked for read.
This file defines the classes PointerTo and ConstPointerTo (and their abbreviations,...
Definition: pointerTo.h:69
const To * get_read_pointer(Thread *current_thread=Thread::get_current_thread()) const
See CopyOnWritePointer::get_read_pointer().
CopyOnWriteObject * get_unsafe_pointer()
Returns an unlocked pointer that you can write to.