// // Copyright 2016 Pixar // // Licensed under the Apache License, Version 2.0 (the "Apache License") // with the following modification; you may not use this file except in // compliance with the Apache License and the following modification to it: // Section 6. Trademarks. is deleted and replaced with: // // 6. Trademarks. This License does not grant permission to use the trade // names, trademarks, service marks, or product names of the Licensor // and its affiliates, except as required to comply with Section 4(c) of // the License and to reproduce the content of the NOTICE file. // // You may obtain a copy of the Apache License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the Apache License with the above modification is // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the Apache License for the specific // language governing permissions and limitations under the Apache License. // #ifndef PXR_BASE_TF_WEAK_PTR_H #define PXR_BASE_TF_WEAK_PTR_H /// \file tf/weakPtr.h /// \ingroup group_tf_Memory /// Pointer storage with deletion detection. #include "pxr/pxr.h" #include "pxr/base/tf/nullPtr.h" #include "pxr/base/tf/refPtr.h" #include "pxr/base/tf/tf.h" #include "pxr/base/tf/weakBase.h" #include "pxr/base/tf/weakPtrFacade.h" #include #include PXR_NAMESPACE_OPEN_SCOPE class TfHash; template class TfRefPtr; template class TfWeakPtr; /// \class TfWeakPtr /// \ingroup group_tf_Memory /// /// Pointer storage with deletion detection. /// /// Overview /// /// A \c TfWeakPtr is used to cache a pointer to an object; before /// retrieving/using this pointer, one queries the \c TfWeakPtr object to /// verify that the objected pointed to has not been deleted in the interim. /// /// \include test/weakPtr.cpp /// /// In the code above, if \c PossiblyDeleteLemur() deletes the object pointed /// to by \c lemur, then the test \c if(lPtr) returns false. Otherwise, it is /// safe to call a method on \c lPtr. /// /// To declare a \c TfWeakPtr, the type \c T must publicly derive from \c /// TfWeakBase. /// /// Basic Use /// /// A \c TfWeakPtr can access \c T's public members by the \c -> operator /// and can be dereferenced by the "\c *" operator. /// /// A \c TfWeakPtr converts to a \c true bool value (for example, in an \c if /// statement) only if the pointer points to an unexpired object. Otherwise, /// if the pointer was either initialized to NULL, or points to an expired /// object, the test returns false. /// /// Occasionally, it is useful to distinguish between a \c TfWeakPtr being /// explicitly initialized to NULL versus a \c TfWeakPtr whose object has /// expired: the member function \c IsInvalid() returns \c true only if the /// pointer points to an expired object. /// /// Opaqueness /// /// See the parallel discussion about these concepts in the documentation for /// \c TfRefPtr; the same concepts apply. /// /// Comparisons, Const and Non-Const, Inheritance and Casting /// /// See the parallel discussion about these concepts in the documentation for /// \c TfRefPtr; the same concepts apply. /// /// While it is possible to create TfWeakPtrs to const contents, we recommend /// against it. TfCreateNonConstWeakPtr will always create a non-const weak /// pointer even when passed a const argument (it casts away const). /// /// The recommendation against use of weak pointers to const content is due to /// the fact that weak pointers cannot be implicitly cast for both inheritance /// (derived to base) and const-ness (non-const to const) at the same time. /// Because of this, using weak pointers to const content is most often much /// more trouble than the benefit it gives. Therefore our policy is to not /// use them. /// /// Pointer Generality /// /// While \c TfWeakPtr is specifically forbidden (you cannot /// construct this kind of object), you can assign any \c TfWeakPtr to a \c /// TfWeakPtr or TfWeakPtr. The only thing you can do with /// the latter is check to see if it points to an object that has expired. /// You cannot manipulate the object itself (i.e. access its member /// functions). /// /// This is useful when you need to watch for object expiration without being /// bound by the type(s) of the objects you're watching. Similarly, you can /// create a TfWeakPtr from a \c TfWeakBase * using \c /// TfCreateWeakPtr(). /// /// Performance /// /// Deriving from \c TfWeakBase results in a single \c TfRefPtr variable being /// added to a class, which is the size of a regular pointer. The cost of /// deleting an object derived from \c TfWeakBase is an extra inline boolean /// comparison, and possible decrement of a reference count if the object's /// address was ever given out as a \c TfWeakPtr. /// /// The cost to create a \c TfWeakPtr is as follows: initial creation of the /// pointer from a \c TfWeakBase object dynamically creates an object called a /// \e remnant, whose size is that of two pointers. Subsequent transfers of /// the same object's address to another \c TfWeakPtr merely bump a reference /// count to the remnant. When all \c TfWeakPtrs to the object (and the object /// itself) are destroyed, the remnant is deleted. An object can have a /// remnant created and destroyed at most once, regardless of how many times /// its address is given out in the form of a \c TfWeakPtr. /// /// Summarizing, the cost of guarding an object is a small amount of extra /// space, and near-zero runtime cost if the guarding is never used. Even if /// the guarding is used, the overhead at deletion time is minimal. /// /// The time to test if a \c TfWeakPtr is NULL, or to call a member function /// through a \c TfWeakPtr is small, involving only a single inline boolean /// comparison. /// template class TfWeakPtr : public TfWeakPtrFacade { public: friend class TfWeakPtrFacadeAccess; template friend class TfWeakPtr; template struct Rebind { typedef TfWeakPtr Type; }; TfWeakPtr() : _rawPtr(0) {} /// Construction, implicit conversion from TfNullPtr. TfWeakPtr(TfNullPtrType) : _rawPtr(0) {} /// Construction, implicit conversion from nullptr. TfWeakPtr(std::nullptr_t) : _rawPtr(nullptr) {} /// Copy construction TfWeakPtr(TfWeakPtr const &p) : _rawPtr(p._rawPtr), _remnant(p._remnant) { } /// Conversion from \a RefPtr where \a U* is convertible to \a T* (this /// pointer type). template TfWeakPtr(TfRefPtr const &p, typename std::enable_if< std::is_convertible::value >::type *dummy = 0) : _rawPtr(get_pointer(p)) { TF_UNUSED(dummy); if (ARCH_LIKELY(_rawPtr)) _remnant = Tf_WeakBaseAccess:: GetRemnant(_rawPtr->__GetTfWeakBase__()); } /// Explicitly construct from a raw pointer \a p. template explicit TfWeakPtr(U *p, typename std::enable_if< std::is_convertible::value>::type *dummy = nullptr) : _rawPtr(p) { TF_UNUSED(dummy); if (ARCH_LIKELY(_rawPtr)) _remnant = Tf_WeakBaseAccess:: GetRemnant(_rawPtr->__GetTfWeakBase__()); } template TfWeakPtr(TfWeakPtr const &p, typename std::enable_if< std::is_convertible::value >::type *dummy = 0) : _rawPtr(p._rawPtr), _remnant(p._remnant) { } bool IsExpired() const { return this->IsInvalid(); } private: T *_FetchPointer() const { if (ARCH_LIKELY(_remnant && _remnant->_IsAlive())) return _rawPtr; return 0; } bool _IsInvalid() const { return _remnant && !_remnant->_IsAlive(); } void const *_GetUniqueIdentifier() const { return _remnant ? _remnant->_GetUniqueIdentifier() : 0; } void _EnableExtraNotification() const { _remnant->EnableNotification(); } T *_rawPtr; mutable TfRefPtr _remnant; }; template TfWeakPtr TfCreateWeakPtr(U *p) { return TfWeakPtr(p); } template TfWeakPtr TfCreateNonConstWeakPtr(U const *p) { return TfWeakPtr(const_cast(p)); } /// Thread-safe creation of a Tf ref pointer from a Tf weak pointer. /// /// This is thread-safe in the sense that the result will be either a ref /// pointer to a live object with non-zero ref-count, or a NULL ref pointer. /// However, this depends on the client to provide a guarantee to protect the /// pointed-to object. /// /// Specifically, the caller must guarantee that the TfRefBase part of the /// pointed-to object is not destroyed during this call. It is fine if the /// destruction process for the object begins (due to the ref-count going to /// zero as another thread drops the last ref) as long as the TfRefBase /// portion is not destroyed. If object destruction begins because the /// ref-count goes to zero before this call completes, this function will /// reliably return a NULL ref pointer. /// /// Note that this is not a general mechanism for safely converting weak /// pointers to ref pointers, because it relies on the type T to provide the /// above guarantee. /// template TfRefPtr TfCreateRefPtrFromProtectedWeakPtr(TfWeakPtr const &p) { typedef typename TfRefPtr::_Counter Counter; if (T *rawPtr = get_pointer(p)) { // Atomically increment the ref-count iff it's nonzero. if (Counter::AddRefIfNonzero(rawPtr)) { // There was at least 1 other ref at the time we acquired our ref, // so this object is safe from destruction. Transfer ownership of // the ref to a new TfRefPtr. return TfCreateRefPtr(rawPtr); } // There were 0 refs to this object, so we know it is expiring and // we cannot use it. } return TfNullPtr; } #if !defined(doxygen) // // Allow TfWeakPtr to be used simply for expiration checking. // template <> class TfWeakPtr { public: TfWeakPtr() { } template TfWeakPtr(TfWeakPtr const& wp) : _remnant(wp._remnant) { } template