Simbody 3.7
CloneOnWritePtr.h
Go to the documentation of this file.
1#ifndef SimTK_SimTKCOMMON_CLONE_ON_WRITE_PTR_H_
2#define SimTK_SimTKCOMMON_CLONE_ON_WRITE_PTR_H_
3
4/* -------------------------------------------------------------------------- *
5 * Simbody(tm): SimTKcommon *
6 * -------------------------------------------------------------------------- *
7 * This is part of the SimTK biosimulation toolkit originating from *
8 * Simbios, the NIH National Center for Physics-Based Simulation of *
9 * Biological Structures at Stanford, funded under the NIH Roadmap for *
10 * Medical Research, grant U54 GM072970. See https://simtk.org/home/simbody. *
11 * *
12 * Portions copyright (c) 2015 Stanford University and the Authors. *
13 * Authors: Michael Sherman *
14 * Contributors: *
15 * *
16 * Licensed under the Apache License, Version 2.0 (the "License"); you may *
17 * not use this file except in compliance with the License. You may obtain a *
18 * copy of the License at http://www.apache.org/licenses/LICENSE-2.0. *
19 * *
20 * Unless required by applicable law or agreed to in writing, software *
21 * distributed under the License is distributed on an "AS IS" BASIS, *
22 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
23 * See the License for the specific language governing permissions and *
24 * limitations under the License. *
25 * -------------------------------------------------------------------------- */
26
28
29#include <memory>
30#include <iosfwd>
31#include <cassert>
32
33namespace SimTK {
34
35//==============================================================================
36// CLONE ON WRITE PTR
37//==============================================================================
59template <class T> class CloneOnWritePtr {
60public:
61 typedef T element_type;
62 typedef T* pointer;
63 typedef T& reference;
64
71 CloneOnWritePtr() noexcept {init();}
72
76 CloneOnWritePtr(std::nullptr_t) noexcept : CloneOnWritePtr() {}
77
82 { if (x) {p=x; count=new long(1);} }
83
89 explicit CloneOnWritePtr(const T* x) : CloneOnWritePtr(cloneOrNull(x)) {}
90
95 explicit CloneOnWritePtr(const T& x) : CloneOnWritePtr(&x) {}
96
103 { shareWith(src); }
104
107 template <class U>
109 { shareWith<U>(src); }
110
115 { moveFrom(std::move(src)); }
116
119 template <class U>
121 { moveFrom<U>(std::move(src)); }
134 if (src.p != p)
135 { reset(); shareWith(src); }
136 return *this;
137 }
138
141 template <class U>
143 if (static_cast<T*>(src.p) != p)
144 { reset(); shareWith<U>(src); }
145 return *this;
146 }
147
155 if (&src != this)
156 { reset(); moveFrom(std::move(src)); }
157 return *this;
158 }
159
162 template <class U>
164 // Can't be the same container since the type is different.
165 reset(); moveFrom<U>(std::move(src));
166 return *this;
167 }
168
175 { reset(cloneOrNull(&x)); return *this; }
176
182 { reset(x); return *this; }
189 ~CloneOnWritePtr() noexcept {reset();}
200 const T* get() const noexcept {return p;}
201
208 T* upd() {detach(); return p;}
209
213 const T& getRef() const {
214 SimTK_ERRCHK(!empty(), "CloneOnWritePtr::getRef()",
215 "An attempt was made to dereference a null pointer.");
216 return *get();
217 }
218
222 T& updRef() {
223 SimTK_ERRCHK(!empty(), "CloneOnWritePtr::updRef()",
224 "An attempt was made to dereference a null pointer.");
225 return *upd();
226 }
227
234 const T* operator->() const { return &getRef(); }
235
238 T* operator->() { return &updRef(); }
239
246 const T& operator*() const {return getRef();}
247
250 T& operator*() {return updRef();}
260 void reset() noexcept {
261 if (empty()) return;
262 if (decr()==0) {delete p; delete count;}
263 init();
264 }
265
271 void reset(T* x) { // could throw when allocating count
272 if (x != p) {
273 reset();
274 if (x) {p=x; count=new long(1);}
275 }
276 }
277
282 void swap(CloneOnWritePtr& other) noexcept {
283 std::swap(p, other.p);
284 std::swap(count, other.count);
285 }
286
291 long use_count() const noexcept {return count ? *count : 0;}
292
296 bool unique() const noexcept {return use_count()==1;}
297
301 bool empty() const noexcept {return !p;} // count should be null also
302
305 explicit operator bool() const noexcept {return !empty();}
306
314 T* release() { // could throw during detach()
315 detach(); // now use count is 1 or 0
316 T* save = p; delete count; init();
317 return save;
318 }
319
329 void detach() { // can throw during clone()
330 if (use_count() > 1)
331 { decr(); p=p->clone(); count=new long(1); }
332 }
335private:
336template <class U> friend class CloneOnWritePtr;
337
338 // If src is non-null, clone it; otherwise return null.
339 static T* cloneOrNull(const T* src) {
340 return src ? src->clone() : nullptr;
341 }
342
343 // Set an empty pointer to share with the given object. Type U* must be
344 // implicitly convertible to type T*.
345 template <class U> void shareWith(const CloneOnWritePtr<U>& src) noexcept {
346 assert(!(p||count));
347 if (!src.empty()) {p=src.p; count=src.count; incr();}
348 }
349
350 // Steal the object and count from the source to initialize this *empty*
351 // pointer, leaving the source empty.
352 template <class U> void moveFrom(CloneOnWritePtr<U>&& src) noexcept {
353 assert(!(p||count));
354 p=src.p; count=src.count; src.init();
355 }
356
357 // Increment/decrement use count and return the result.
358 long incr() const noexcept {assert(count && *count>=0); return ++(*count);}
359 long decr() const noexcept {assert(count && *count>=1); return --(*count);}
360
361 void init() noexcept {p=nullptr; count=nullptr;}
362
363 // Can't use std::shared_ptr here due to lack of release() method.
364 T* p; // this may be null
365 long* count; // if p is null so is count
366};
367
368
369//==============================================================================
370// SimTK namespace-scope functions
371//==============================================================================
372// These namespace-scope functions will be resolved by the compiler using
373// "Koenig lookup" which examines the arguments' namespaces first.
374// See Herb Sutter's discussion here: http://www.gotw.ca/publications/mill08.htm.
375
380template <class T> inline void
382 p1.swap(p2);
383}
384
388template <class charT, class traits, class T>
389inline std::basic_ostream<charT,traits>&
390operator<<(std::basic_ostream<charT,traits>& os,
391 const CloneOnWritePtr<T>& p)
392{ os << p.get(); return os; }
393
399template <class T, class U>
400inline bool operator==(const CloneOnWritePtr<T>& lhs,
401 const CloneOnWritePtr<U>& rhs)
402{ return lhs.get() == rhs.get(); }
403
406template <class T>
407inline bool operator==(const CloneOnWritePtr<T>& lhs, std::nullptr_t)
408{ return lhs.empty(); }
409
412template <class T>
413inline bool operator==(std::nullptr_t, const CloneOnWritePtr<T>& rhs)
414{ return rhs.empty(); }
415
422template <class T, class U>
423inline bool operator<(const CloneOnWritePtr<T>& lhs,
424 const CloneOnWritePtr<U>& rhs)
425{ return lhs.get() < rhs.get(); }
426
431template <class T>
432inline bool operator<(const CloneOnWritePtr<T>& lhs, std::nullptr_t)
433{ return false; }
434
439template <class T>
440inline bool operator<(std::nullptr_t, const CloneOnWritePtr<T>& rhs)
441{ return !rhs.empty(); }
442
443
444// These functions are derived from operator== and operator<.
445
448template <class T, class U>
449inline bool operator!=(const CloneOnWritePtr<T>& lhs,
450 const CloneOnWritePtr<U>& rhs)
451{ return !(lhs==rhs); }
454template <class T>
455inline bool operator!=(const CloneOnWritePtr<T>& lhs, std::nullptr_t)
456{ return !(lhs==nullptr); }
459template <class T>
460inline bool operator!=(std::nullptr_t, const CloneOnWritePtr<T>& rhs)
461{ return !(nullptr==rhs); }
462
465template <class T, class U>
466inline bool operator>(const CloneOnWritePtr<T>& lhs,
467 const CloneOnWritePtr<U>& rhs)
468{ return rhs < lhs; }
471template <class T>
472inline bool operator>(const CloneOnWritePtr<T>& lhs, std::nullptr_t)
473{ return nullptr < lhs; }
474
477template <class T>
478inline bool operator>(std::nullptr_t, const CloneOnWritePtr<T>& rhs)
479{ return rhs < nullptr; }
480
481
484template <class T, class U>
485inline bool operator>=(const CloneOnWritePtr<T>& lhs,
486 const CloneOnWritePtr<U>& rhs)
487{ return !(lhs < rhs); }
490template <class T>
491inline bool operator>=(const CloneOnWritePtr<T>& lhs, std::nullptr_t)
492{ return !(lhs < nullptr); }
493
496template <class T>
497inline bool operator>=(std::nullptr_t, const CloneOnWritePtr<T>& rhs)
498{ return !(nullptr < rhs); }
499
500
504template <class T, class U>
505inline bool operator<=(const CloneOnWritePtr<T>& lhs,
506 const CloneOnWritePtr<U>& rhs)
507{ return !(rhs < lhs); }
511template <class T>
512inline bool operator<=(const CloneOnWritePtr<T>& lhs, std::nullptr_t)
513{ return !(nullptr < lhs); }
517template <class T>
518inline bool operator<=(std::nullptr_t, const CloneOnWritePtr<T>& rhs)
519{ return !(rhs < nullptr); }
520
521} // namespace SimTK
522
523#endif // SimTK_SimTKCOMMON_CLONE_ON_WRITE_PTR_H_
#define SimTK_ERRCHK(cond, whereChecked, msg)
Definition: ExceptionMacros.h:324
Mandatory first inclusion for any Simbody source or header file.
Smart pointer with deep copy semantics but with the copying delayed until an attempt is made to write...
Definition: CloneOnWritePtr.h:59
CloneOnWritePtr & operator=(CloneOnWritePtr< U > &&src) noexcept
Move assignment from a compatible CloneOnWritePtr.
Definition: CloneOnWritePtr.h:163
CloneOnWritePtr & operator=(const T &x)
This form of assignment replaces the currently-held object by a heap-allocated copy of the source obj...
Definition: CloneOnWritePtr.h:174
bool operator<=(const CloneOnWritePtr< T > &lhs, std::nullptr_t)
nullptr less-or-equal test defined as !(nullptr < lhs) (note reversed arguments).
Definition: CloneOnWritePtr.h:512
T & updRef()
Clone if necessary to ensure the contained object is not shared, then return a writable reference to ...
Definition: CloneOnWritePtr.h:222
CloneOnWritePtr & operator=(const CloneOnWritePtr< U > &src) noexcept
Copy assignment from a compatible CloneOnWritePtr.
Definition: CloneOnWritePtr.h:142
T * upd()
Clone if necessary to ensure the contained object is not shared, then return a writable pointer to th...
Definition: CloneOnWritePtr.h:208
CloneOnWritePtr(const T *x)
Given a pointer to a read-only object, create a new heap-allocated copy of that object via its clone(...
Definition: CloneOnWritePtr.h:89
bool operator!=(const CloneOnWritePtr< T > &lhs, std::nullptr_t)
nullptr inequality test defined as !(lhs==nullptr).
Definition: CloneOnWritePtr.h:455
CloneOnWritePtr(T *x)
Given a pointer to a writable heap-allocated object, take over ownership of that object.
Definition: CloneOnWritePtr.h:81
bool operator>=(const CloneOnWritePtr< T > &lhs, std::nullptr_t)
nullptr greater-or-equal test defined as !(lhs < nullptr).
Definition: CloneOnWritePtr.h:491
bool operator>=(const CloneOnWritePtr< T > &lhs, const CloneOnWritePtr< U > &rhs)
Pointer greater-or-equal test defined as !(lhs < rhs).
Definition: CloneOnWritePtr.h:485
T * release()
(Advanced) Remove the contained object from management by this container and transfer ownership to th...
Definition: CloneOnWritePtr.h:314
bool operator>(std::nullptr_t, const CloneOnWritePtr< T > &rhs)
nullptr greater-than test defined as rhs < nullptr.
Definition: CloneOnWritePtr.h:478
CloneOnWritePtr(CloneOnWritePtr &&src) noexcept
Move constructor is very fast and leaves the source empty.
Definition: CloneOnWritePtr.h:114
CloneOnWritePtr(const CloneOnWritePtr< U > &src) noexcept
Copy construction from a compatible CloneOnWritePtr.
Definition: CloneOnWritePtr.h:108
CloneOnWritePtr() noexcept
Default constructor stores a nullptr and sets use count to zero.
Definition: CloneOnWritePtr.h:71
bool empty() const noexcept
Return true if this container is empty, which is the state the container is in immediately after defa...
Definition: CloneOnWritePtr.h:301
bool operator>=(std::nullptr_t, const CloneOnWritePtr< T > &rhs)
nullptr greater-or-equal test defined as !(nullptr < rhs).
Definition: CloneOnWritePtr.h:497
CloneOnWritePtr & operator=(const CloneOnWritePtr &src) noexcept
Copy assignment replaces the currently-held object by a deferred copy of the object held in the sourc...
Definition: CloneOnWritePtr.h:133
const T & getRef() const
Return a const reference to the contained object.
Definition: CloneOnWritePtr.h:213
bool operator==(std::nullptr_t, const CloneOnWritePtr< T > &rhs)
Comparison against nullptr; same as rhs.empty().
Definition: CloneOnWritePtr.h:413
const T & operator*() const
This "dereference" operator returns a const reference to the contained object.
Definition: CloneOnWritePtr.h:246
CloneOnWritePtr(const CloneOnWritePtr &src) noexcept
Copy constructor is deep but deferred so very fast here; the new CloneOnWritePtr object initially sha...
Definition: CloneOnWritePtr.h:102
bool operator<=(std::nullptr_t, const CloneOnWritePtr< T > &rhs)
nullptr less-or-equal test defined as !(rhs < nullptr) (note reversed arguments).
Definition: CloneOnWritePtr.h:518
CloneOnWritePtr & operator=(CloneOnWritePtr &&src) noexcept
Move assignment replaces the currently-held object by the source object, leaving the source empty.
Definition: CloneOnWritePtr.h:154
bool operator==(const CloneOnWritePtr< T > &lhs, std::nullptr_t)
Comparison against nullptr; same as lhs.empty().
Definition: CloneOnWritePtr.h:407
CloneOnWritePtr(CloneOnWritePtr< U > &&src) noexcept
Move construction from a compatible CloneOnWritePtr.
Definition: CloneOnWritePtr.h:120
~CloneOnWritePtr() noexcept
Destructor decrements the reference count and deletes the object if the count goes to zero.
Definition: CloneOnWritePtr.h:189
void swap(CloneOnWritePtr &other) noexcept
Swap the contents of this CloneOnWritePtr with another one, with ownership changing hands but no copy...
Definition: CloneOnWritePtr.h:282
bool operator<=(const CloneOnWritePtr< T > &lhs, const CloneOnWritePtr< U > &rhs)
Pointer less-or-equal test defined as !(rhs < lhs) (note reversed arguments).
Definition: CloneOnWritePtr.h:505
void reset() noexcept
Make this container empty, decrementing the use count of the contained object (if any),...
Definition: CloneOnWritePtr.h:260
T & reference
Type of a reference to the contained object.
Definition: CloneOnWritePtr.h:63
CloneOnWritePtr(std::nullptr_t) noexcept
Constructor from nullptr is the same as the default constructor.
Definition: CloneOnWritePtr.h:76
long use_count() const noexcept
Return count of how many CloneOnWritePtr objects are currently sharing the referenced object.
Definition: CloneOnWritePtr.h:291
void detach()
(Advanced) Force the contained object to be unique, that is, not shared with any other container.
Definition: CloneOnWritePtr.h:329
bool operator<(const CloneOnWritePtr< T > &lhs, std::nullptr_t)
Less-than comparison against a nullptr.
Definition: CloneOnWritePtr.h:432
bool operator!=(std::nullptr_t, const CloneOnWritePtr< T > &rhs)
nullptr inequality test defined as !(nullptr==rhs).
Definition: CloneOnWritePtr.h:460
bool operator<(const CloneOnWritePtr< T > &lhs, const CloneOnWritePtr< U > &rhs)
Less-than operator for two compatible CloneOnWritePtr containers, comparing the pointers,...
Definition: CloneOnWritePtr.h:423
bool operator<(std::nullptr_t, const CloneOnWritePtr< T > &rhs)
Less-than comparison of a nullptr against this container.
Definition: CloneOnWritePtr.h:440
const T * get() const noexcept
Return a const pointer to the contained object if any, or nullptr.
Definition: CloneOnWritePtr.h:200
CloneOnWritePtr(const T &x)
Given a read-only reference to an object, create a new heap-allocated copy of that object via its clo...
Definition: CloneOnWritePtr.h:95
bool operator==(const CloneOnWritePtr< T > &lhs, const CloneOnWritePtr< U > &rhs)
Compare for equality the managed pointers contained in two compatible CloneOnWritePtr containers.
Definition: CloneOnWritePtr.h:400
bool operator!=(const CloneOnWritePtr< T > &lhs, const CloneOnWritePtr< U > &rhs)
Pointer inequality test defined as !(lhs==rhs).
Definition: CloneOnWritePtr.h:449
T & operator*()
Clone if necessary, then return a writable reference to the contained object.
Definition: CloneOnWritePtr.h:250
bool unique() const noexcept
Is this the only user of the referenced object? Note that this means there is exactly one; if the man...
Definition: CloneOnWritePtr.h:296
const T * operator->() const
Dereference a const pointer to the contained object.
Definition: CloneOnWritePtr.h:234
T * pointer
Type of a pointer to the contained object.
Definition: CloneOnWritePtr.h:62
T * operator->()
Clone if necessary, then dereference a writable pointer to the contained object.
Definition: CloneOnWritePtr.h:238
void reset(T *x)
Replace the contents of this container with the supplied heap-allocated object, taking over ownership...
Definition: CloneOnWritePtr.h:271
T element_type
Type of the contained object.
Definition: CloneOnWritePtr.h:61
bool operator>(const CloneOnWritePtr< T > &lhs, const CloneOnWritePtr< U > &rhs)
Pointer greater-than test defined as rhs < lhs.
Definition: CloneOnWritePtr.h:466
CloneOnWritePtr & operator=(T *x) noexcept
This form of assignment replaces the currently-held object by the given source object and takes over ...
Definition: CloneOnWritePtr.h:181
bool operator>(const CloneOnWritePtr< T > &lhs, std::nullptr_t)
nullptr greater-than test defined as nullptr < lhs.
Definition: CloneOnWritePtr.h:472
This is the top-level SimTK namespace into which all SimTK names are placed to avoid collision with o...
Definition: Assembler.h:37
std::ostream & operator<<(std::ostream &o, const ContactForce &f)
Definition: CompliantContactSubsystem.h:387