| # if !defined(TS_INTRUSIVE_PTR_HEADER) |
| # define TS_INTRUSIVE_PTR_HEADER |
| |
| /** @file |
| |
| This is a simple shared pointer class for restricted use. It is not a |
| completely general class. The most significant missing feature is the |
| lack of thread safety. For its intended use, this is acceptable and |
| provides a performance improvement. However, it does restrict how the |
| class may be used. |
| |
| This style of shared pointer also requires explicit support from the |
| target class, which must provide an internal reference counter. |
| |
| @section license License |
| |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance |
| with the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| */ |
| |
| # include <sys/types.h> |
| # include <assert.h> |
| # include <functional> |
| |
| namespace ts { |
| |
| class IntrusivePtrCounter; |
| |
| /** This class exists solely to be declared a friend of @c IntrusivePtrCounter. |
| |
| @internal This is done because we can't declare the template a |
| friend, so rather than burden the client with the declaration we |
| do it here. It provides a single method that allows the smart pointer |
| to get access to the protected reference count. |
| |
| */ |
| class IntrusivePtrBase { |
| public: |
| /// Type used for reference counter. |
| typedef long Counter; |
| protected: |
| Counter* getCounter( |
| IntrusivePtrCounter* c ///< Cast object with reference counter. |
| ) const; |
| }; |
| /* ----------------------------------------------------------------------- */ |
| /* ----------------------------------------------------------------------- */ |
| /** Reference counter mixin. |
| |
| To add support for @c IntrusivePtr to class @a T, it |
| should inherit from @c IntrusivePtrCounter<T> in order to |
| |
| - provide a reference count member |
| - force the reference count to initialize to zero |
| - define the add and release global functions required by @c IntrusivePtr |
| |
| In general this class should be inherited publicly. This will |
| provide methods which mimic the @c Boost.shared_ptr interface ( @c |
| unique() , @c use_count() ). |
| |
| If this class is not inherited publically or the destructor is |
| non-public then the host class (@a T) must declare this class ( @c |
| reference_counter<T> ) as a friend. |
| |
| @internal Due to changes in the C++ standard and design decisions |
| in gcc, it is no longer possible to declare a template parameter |
| as a friend class. (Basically, you can't use a typedef in a |
| friend declaration and gcc treats template parameters as |
| typedefs). |
| |
| @note You can use this with insulated (by name only) classes. The |
| important thing is to make sure that any such class that uses @c |
| IntrusivePtr has all of its constructors and destructors declared |
| in the header and defined in the implementation translation |
| unit. If the compiler generates any of those, it will not compile |
| due to missing functions or methods |
| |
| */ |
| class IntrusivePtrCounter { |
| friend class IntrusivePtrBase; |
| public: |
| /** Copy constructor. |
| |
| @internal We have to define this to explicitly _not_ copy the |
| reference count. Otherwise any client that uses a default copy |
| constructor will _copy the ref count into the new object_. That |
| way lies madness. |
| */ |
| |
| IntrusivePtrCounter( |
| IntrusivePtrCounter const& ///< Source object. |
| ); |
| |
| /** Assignment operator. |
| |
| @internal We need this for the same reason as the copy |
| constructor. The reference counter must not participate in |
| assignment. |
| */ |
| IntrusivePtrCounter& operator = ( |
| IntrusivePtrCounter const& |
| ); |
| |
| protected: |
| IntrusivePtrBase::Counter m_intrusive_pointer_reference_count; |
| /// Default constructor (0 init counter). |
| /// @internal Only subclasses can access this. |
| IntrusivePtrCounter(); |
| }; |
| /* ----------------------------------------------------------------------- */ |
| /* ----------------------------------------------------------------------- */ |
| /** Shared pointer. |
| |
| This is a reference counted smart pointer. A single object is jointly |
| ownded by a set of pointers. When the last of the pointers is destructed |
| the target object is also destructed. |
| |
| The smart pointer actions can be changed through class specific policy |
| by specializing the @c IntrusivePtrPolicy template class. |
| */ |
| template < typename T > |
| class IntrusivePtr : private IntrusivePtrBase { |
| private: /* don't pollute client with these typedefs */ |
| typedef IntrusivePtrBase super; ///< Parent type. |
| typedef IntrusivePtr self; ///< Self reference type. |
| |
| public: |
| /// Promote type for reference counter. |
| typedef super::Counter Counter; |
| |
| /// Default constructor (0 initialized). |
| IntrusivePtr(); |
| /// Construct from instance. |
| /// The instance becomes referenced and owned by the pointer. |
| IntrusivePtr(T* obj); |
| /// Destructor. |
| ~IntrusivePtr(); |
| |
| /// Copy constructor. |
| IntrusivePtr(const self& src); |
| /// Self assignement. |
| self& operator = (const self& src); |
| /** Assign from instance. |
| The instance becomes referenced and owned by the pointer. |
| The reference to the current object is dropped. |
| */ |
| self& operator = ( |
| T* obj ///< Target instance. |
| ); |
| |
| /** Assign from instance. |
| The instance becomes referenced and owned by the pointer. |
| The reference to the current object is dropped. |
| @note A synonym for @c operator= for compatibility. |
| */ |
| self& assign ( |
| T* obj ///< Target instance. |
| ); |
| |
| /** Assign from instance. |
| The instance becomes referenced and owned by the pointer. |
| The reference to the current object is dropped. |
| */ |
| void reset(T* obj); |
| /** Clear reference without cleanup. |
| |
| This unsets this smart pointer and decrements the reference |
| count, but does @b not perform any finalization on the |
| target object. This can easily lead to memory leaks and |
| in some sense vitiates the point of this class, but it is |
| occasionally the right thing to do. Use with caution. |
| |
| @return @c true if there are no references upon return, |
| @c false if the reference count is not zero. |
| */ |
| bool release(); |
| |
| /// Test if the pointer is zero (@c NULL). |
| bool isNull() const; |
| |
| /// Member dereference. |
| T* operator -> () const; |
| /// Dereference. |
| T& operator * () const; |
| /// Access raw pointer. |
| T* get() const; |
| |
| /** User conversion to raw pointer. |
| |
| @internal allow implicit conversion to the underlying |
| pointer. This allows for the form "if (handle)" and is not |
| particularly dangerous (as it would be for a scope_ptr or |
| shared_ptr) because the counter is carried with the object and |
| so can't get lost or duplicated. |
| |
| */ |
| operator T* () const; |
| |
| /** Cross type construction. |
| This succeeds if an @a X* can be implicitly converted to a @a T*. |
| */ |
| template < |
| typename X ///< Foreign pointer type. |
| > IntrusivePtr( |
| IntrusivePtr<X> const& that ///< Foreign pointer. |
| ); |
| |
| /** Cross type assignment. |
| This succeeds if an @a X* can be implicitily converted to a @a T*. |
| */ |
| template < |
| typename X ///< Foreign pointer type. |
| > self& operator = ( |
| IntrusivePtr<X> const& that ///< Foreign pointer. |
| ); |
| |
| /// Check for multiple references. |
| /// @return @c true if more than one smart pointer references the object, |
| /// @c false otherwise. |
| bool isShared() const; |
| /// Check for a single reference (@c shared_ptr compatibility) |
| /// @return @c true if this object is not shared. |
| bool unique() const; |
| /// Reference count. |
| /// @return Number of references. |
| Counter useCount() const; |
| private: |
| T* m_obj; ///< Pointer to object. |
| |
| /// Reference @a obj. |
| void set( |
| T* obj ///< Target object. |
| ); |
| /// Drop the current reference. |
| void unset(); |
| |
| /// Get a pointer to the reference counter of the target object. |
| Counter* getCounter() const; |
| }; |
| |
| /** Pointer dynamic cast. |
| This allows a smart pointer to be cast from one type to another. |
| It must be used when the types do not implicitly convert (generally |
| a downcast). |
| |
| @code |
| class A { ... }; |
| class B : public A { ... }; |
| IntrusivePtr<A> really_b(new B); |
| InstruivePtr<B> the_b; |
| the_b = dynamic_ptr_cast<B>(really_b); |
| @endcode |
| */ |
| template < |
| typename T, ///< Target type. |
| typename X ///< Source type. |
| > IntrusivePtr<T> dynamic_ptr_cast( |
| IntrusivePtr<X> const& src ///< Source pointer. |
| ) { |
| return IntrusivePtr<T>(dynamic_cast<T*>(src.get())); |
| } |
| |
| /** Pointer cast. |
| This allows a smart pointer to be cast from one type to another. |
| It must be used when the types do not implicitly convert (generally |
| a downcast). This uses @c static_cast and so performs only compile |
| time checks. |
| |
| @code |
| class A { ... }; |
| class B : public A { ... }; |
| IntrusivePtr<A> really_b(new B); |
| IntrusivePtr<B> the_b; |
| the_b = ptr_cast<B>(really_b); |
| @endcode |
| */ |
| template < |
| typename T, ///< Target type. |
| typename X ///< Source type. |
| > IntrusivePtr<T> ptr_cast( |
| IntrusivePtr<X> const& src ///< Source pointer. |
| ) { |
| return IntrusivePtr<T>(static_cast<T*>(src.get())); |
| } |
| /* ----------------------------------------------------------------------- */ |
| /* ----------------------------------------------------------------------- */ |
| /** Default policy class for intrusive pointers. |
| |
| This allows per type policy, although not per target instance. |
| Clients can override policy by specializing this class for the |
| target type. |
| |
| @code |
| template <> IntrusivePtrPolicy<SomeType> |
| : IntrusivePtrDefaultPolicy { |
| ... Redefinition of methods and nested types ... |
| }; |
| @endcode |
| |
| The inherited class will provide the default definitions so you can |
| override only what is different. Although this can be omitted if you |
| override everything, it is more robust for maintenance to inherit |
| anyway. |
| */ |
| |
| template <typename T> |
| class IntrusivePtrPolicy { |
| public: |
| /// Called when the pointer is dereferenced. |
| /// Default is empty (no action). |
| static void dereferenceCheck( |
| T* ///< Target object. |
| ); |
| |
| /** Perform clean up on a target object that is no longer referenced. |
| |
| Default is calling @c delete. Any specialization that overrides this |
| @b must clean up the object. The primary use of this is to perform |
| a clean up other than @c delete. |
| |
| @note When this is called, the target object reference count |
| is zero. If it is necessary to pass a smart pointer to the |
| target object, it will be necessary to call |
| @c IntrusivePtr::release to drop the reference without |
| another finalization. Further care must be taken that none of |
| the called logic keeps a copy of the smart pointer. Use with |
| caution. |
| */ |
| static void finalize( |
| T* t ///< Target object. |
| ); |
| /// Strict weak order for STL containers. |
| class Order |
| : public std::binary_function< IntrusivePtr<T>, IntrusivePtr<T>, bool> { |
| public: |
| /// Default constructor. |
| Order() { |
| } |
| /// Compare by raw pointer. |
| bool operator() ( |
| IntrusivePtr<T> const& lhs, ///< Left hand operand. |
| IntrusivePtr<T> const& rhs ///< Right hand operand. |
| ) const; |
| }; |
| }; |
| |
| struct IntrusivePtrDefaultPolicyTag {}; |
| typedef IntrusivePtrPolicy<IntrusivePtrDefaultPolicyTag> IntrusivePtrDefaultPolicy; |
| /* ----------------------------------------------------------------------- */ |
| /* ----------------------------------------------------------------------- */ |
| /* Inline Methods */ |
| inline IntrusivePtrCounter::IntrusivePtrCounter() |
| : m_intrusive_pointer_reference_count(0) { |
| } |
| |
| inline IntrusivePtrCounter::IntrusivePtrCounter(IntrusivePtrCounter const&) |
| : m_intrusive_pointer_reference_count(0) { |
| } |
| |
| inline IntrusivePtrCounter& |
| IntrusivePtrCounter::operator = (IntrusivePtrCounter const&) { |
| return *this; |
| } |
| |
| inline IntrusivePtrBase::Counter* |
| IntrusivePtrBase::getCounter(IntrusivePtrCounter* c) const { |
| return &(c->m_intrusive_pointer_reference_count); |
| } |
| /* ----------------------------------------------------------------------- */ |
| /* ----------------------------------------------------------------------- */ |
| template < typename T > void |
| IntrusivePtrPolicy<T>::dereferenceCheck(T*) { |
| } |
| |
| template < typename T > void |
| IntrusivePtrPolicy<T>::finalize(T* obj) { |
| delete obj; |
| } |
| |
| template < typename T > bool |
| IntrusivePtrPolicy<T>::Order::operator()( |
| IntrusivePtr<T> const& lhs, |
| IntrusivePtr<T> const& rhs |
| ) const { |
| return lhs.get() < rhs.get(); |
| } |
| /* ----------------------------------------------------------------------- */ |
| /* ----------------------------------------------------------------------- */ |
| template < typename T > |
| IntrusivePtr<T>::IntrusivePtr() |
| : m_obj(0) { |
| } |
| |
| template < typename T > |
| IntrusivePtr<T>::IntrusivePtr(T* obj) { |
| this->set(obj); |
| } |
| |
| template < typename T > |
| IntrusivePtr<T>::~IntrusivePtr() { |
| this->unset(); |
| } |
| |
| template < typename T > |
| IntrusivePtr<T>::IntrusivePtr(const self& that) { |
| this->set(that.m_obj); |
| } |
| |
| template < typename T > |
| template < typename X > |
| IntrusivePtr<T>::IntrusivePtr( |
| IntrusivePtr<X> const& that ///< Foreign pointer. |
| ) : super(that.get()) { |
| } |
| |
| template < typename T > IntrusivePtr<T>& |
| IntrusivePtr<T>::operator = (const self& that) { |
| this->reset(that.m_obj); |
| return *this; |
| } |
| |
| template < typename T > |
| template < typename X > |
| IntrusivePtr<T>& |
| IntrusivePtr<T>::operator = ( |
| IntrusivePtr<X> const& that ///< Foreign pointer. |
| ) { |
| this->reset(that.get()); |
| return *this; |
| } |
| |
| template < typename T > IntrusivePtr<T>& |
| IntrusivePtr<T>::operator = (T* obj) { |
| this->reset(obj); |
| return *this; |
| } |
| |
| template < typename T > IntrusivePtr<T>& |
| IntrusivePtr<T>::assign (T* obj) { |
| return *this = obj; |
| } |
| |
| template < typename T > T* |
| IntrusivePtr<T>::operator -> () const { |
| IntrusivePtrPolicy<T>::dereferenceCheck(m_obj); |
| return m_obj; |
| } |
| |
| template < typename T > T& |
| IntrusivePtr<T>::operator * () const { |
| IntrusivePtrPolicy<T>::dereferenceCheck(m_obj); |
| return *m_obj; |
| } |
| |
| template < typename T > T* |
| IntrusivePtr<T>::get() const { |
| IntrusivePtrPolicy<T>::dereferenceCheck(m_obj); |
| return m_obj; |
| } |
| |
| template < typename T > typename IntrusivePtr<T>::Counter* |
| IntrusivePtr<T>::getCounter() const { |
| return super::getCounter(static_cast<IntrusivePtrCounter*>(m_obj)); |
| } |
| |
| /* The Set/Unset methods are the basic implementation of our |
| * reference counting. The Reset method is the standard way |
| * of invoking the pair, although splitting them allows some |
| * additional efficiency in certain situations. |
| */ |
| |
| /* set and unset are two half operations that don't do checks. |
| It is the callers responsibility to do that. |
| */ |
| |
| template < typename T > void |
| IntrusivePtr<T>::unset() { |
| if (0 != m_obj) { |
| /* magic: our target is required to inherit from IntrusivePtrCounter, |
| * which provides a protected counter variable and access via our |
| * super class. We call the super class method to get a raw pointer |
| * to the counter variable. |
| */ |
| Counter* cp = this->getCounter(); |
| |
| /* If you hit this assert you've got a cycle of objects that |
| reference each other. A delete in the cycle will eventually |
| result in one of the objects getting deleted twice, which is |
| what this assert indicates. |
| */ |
| assert(*cp); |
| |
| if (0 == --*cp) { |
| IntrusivePtrPolicy<T>::finalize(m_obj); |
| } |
| m_obj = 0; |
| } |
| } |
| |
| template < typename T > void |
| IntrusivePtr<T>::set(T* obj) { |
| m_obj = obj; /* update to new object */ |
| if (0 != m_obj) /* if a real object, bump the ref count */ |
| ++(*(this->getCounter())); |
| } |
| |
| template < typename T > void |
| IntrusivePtr<T>::reset(T* obj) { |
| if (obj != m_obj) { |
| this->unset(); |
| this->set(obj); |
| } |
| } |
| |
| template < typename T > bool |
| IntrusivePtr<T>::release() { |
| bool zret = true; |
| if (m_obj) { |
| Counter* cp = this->getCounter(); |
| zret = *cp <= 1; |
| // If the client is using this method, they're doing something funky |
| // so be extra careful with the reference count. |
| if (*cp > 0) --*cp; |
| m_obj = 0; |
| } |
| return zret; |
| } |
| |
| /* Simple method to check for invalid pointer */ |
| template < typename T > bool |
| IntrusivePtr<T>::isNull() const { |
| return 0 == m_obj; |
| } |
| |
| /* Pointer comparison */ |
| template < typename T > bool |
| operator == (IntrusivePtr<T> const& lhs, IntrusivePtr<T> const& rhs) { |
| return lhs.get() == rhs.get(); |
| } |
| |
| template < typename T > bool |
| operator != (IntrusivePtr<T> const& lhs, IntrusivePtr<T> const& rhs) { |
| return lhs.get() != rhs.get(); |
| } |
| |
| template < typename T > bool |
| operator < (IntrusivePtr<T> const& lhs, IntrusivePtr<T> const& rhs) { |
| return lhs.get() < rhs.get(); |
| } |
| |
| template < typename T > bool |
| operator == (IntrusivePtr<T> const& lhs, int rhs) { |
| assert(0 == rhs); |
| return lhs.get() == 0; |
| } |
| |
| template < typename T > bool |
| operator == (int lhs, IntrusivePtr<T> const& rhs) { |
| assert(0 == lhs); |
| return rhs.get() == 0; |
| } |
| |
| template < typename T > bool |
| operator != (int lhs, IntrusivePtr<T> const& rhs) { |
| return !(lhs == rhs); |
| } |
| |
| template < typename T > bool |
| operator != (IntrusivePtr<T> const& lhs, int rhs) { |
| return !(lhs == rhs); |
| } |
| |
| template < typename T > |
| IntrusivePtr<T>::operator T* () const { |
| return m_obj; |
| } |
| |
| template < typename T> bool |
| IntrusivePtr<T>::isShared() const { |
| return m_obj && *(this->getCounter()) > 1; |
| } |
| |
| template < typename T> bool |
| IntrusivePtr<T>::unique() const { |
| return 0 == m_obj || *(this->getCounter()) <= 1; |
| } |
| |
| template < typename T> typename IntrusivePtr<T>::Counter |
| IntrusivePtr<T>::useCount() const { |
| return m_obj ? *(this->getCounter()) : 0; |
| } |
| /* ----------------------------------------------------------------------- */ |
| /* ----------------------------------------------------------------------- */ |
| } // namespace ats |
| /* ----------------------------------------------------------------------- */ |
| # endif // TS_INTRUSIVE_PTR_HEADER |