Simbody 3.7
Loading...
Searching...
No Matches
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