/* * Copyright (c) 2013, Ford Motor Company * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following * disclaimer in the documentation and/or other materials provided with the * distribution. * * Neither the name of the Ford Motor Company nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef SRC_COMPONENTS_INCLUDE_UTILS_SHARED_PTR_H_ #define SRC_COMPONENTS_INCLUDE_UTILS_SHARED_PTR_H_ #include #include #include #include "utils/macro.h" #include "utils/atomic.h" namespace utils { /** * @brief Shared pointer. * * Pointer to an object with reference counting. * Object will be automatically deallocated when last shared * pointer is destroyed. * * @tparam ObjectType Type of wrapped object. **/ template class SharedPtr { public: //std smart pointer compability typedef ObjectType element_type; /** * @brief Constructor. * * Initialize shared pointer with wrapped object. * Reference counter will be initialized to 1. * * @param Object Wrapped object. **/ SharedPtr(ObjectType* Object); SharedPtr(); /** * @brief Copy constructor. * * Initialize shared pointer with another shared pointer. * Reference counter will be incremented. * * @param Other Other shared pointer. **/ SharedPtr(const SharedPtr& Other); /** * @brief Copy constructor. * * Initialize shared pointer with another shared pointer. * Reference counter will be incremented. * * @tparam OtherObjectType Type of other object pointer. This * allows creating a shared pointer to an * intstance of a base class from a shared * pointer to an instance of a class * inherited from this base class. * If OtherObjectType is not implicitly * convertible to ObjectType it will * cause a compile error. * * @param Other Other shared pointer. **/ template SharedPtr(const SharedPtr& Other); /** * @brief Destructor. * * Decrement reference counter and destroy wrapped object * if reference counter reaches zero. **/ ~SharedPtr(); /** * @brief Assignment operator. * * Drop reference to currently referenced object and add * reference to assigned object. * * @param Other Shared pointer to an object * that must be referenced. * * @return Reference to this shared pointer. **/ SharedPtr& operator =(const SharedPtr& Other); bool operator ==(const SharedPtr& Other) const; bool operator< (const SharedPtr& other) const; /** * @brief Assignment operator. * * Drop reference to currently referenced object and add * reference to assigned object. * * @tparam OtherObjectType Type of other object pointer. This * allows creating a shared pointer to an * intstance of a base class from a shared * pointer to an instance of a class * inherited from this base class. * If OtherObjectType is not implicitly * convertible to ObjectType it will * cause a compile error. * * @param Other Shared pointer to an object * that must be referenced. * * @return Reference to this shared pointer. **/ template SharedPtr& operator =(const SharedPtr& Other); template static SharedPtr static_pointer_cast( const SharedPtr& pointer); template static SharedPtr dynamic_pointer_cast( const SharedPtr& pointer); /** * @brief Member access operator. * * @return Wrapped object. **/ ObjectType* operator->() const; ObjectType& operator*() const; operator bool() const; void reset(); void reset(ObjectType* other); ObjectType* get() const; /** * @return true if mObject not NULL */ bool valid() const; private: void reset_impl(ObjectType* other); // TSharedPtr needs access to other TSharedPtr private members // for shared pointers type casts. template friend class SharedPtr; /** * @brief Drop reference to wrapped object. * * If reference counter reaches zero object and its reference * counter will be deallocated. **/ void dropReference(); /** * @brief Wrapped object. **/ ObjectType* mObject; /** * @brief Pointer to reference counter. **/ uint32_t* mReferenceCounter; void release(); }; template inline utils::SharedPtr::SharedPtr(ObjectType* Object) : mObject(NULL), mReferenceCounter(new uint32_t(1)) { DCHECK(Object != NULL); mObject = Object; } template inline utils::SharedPtr::SharedPtr() : mObject(0), mReferenceCounter(0) { } template inline utils::SharedPtr::SharedPtr( const SharedPtr& Other) : mObject(0), mReferenceCounter(0) { *this = Other; } template template inline utils::SharedPtr::SharedPtr( const SharedPtr& Other) : mObject(0), mReferenceCounter(0) { *this = Other; } template inline utils::SharedPtr::~SharedPtr() { dropReference(); } template inline utils::SharedPtr& utils::SharedPtr::operator=(const SharedPtr& Other) { return operator=(Other); } template inline bool utils::SharedPtr::operator ==( const SharedPtr& Other) const { return (mObject == Other.mObject); } template inline bool utils::SharedPtr::operator< ( const SharedPtr& other) const { return (mObject < other.mObject); } template template inline utils::SharedPtr& utils::SharedPtr::operator=( const SharedPtr& Other) { dropReference(); mObject = Other.mObject; mReferenceCounter = Other.mReferenceCounter; if (0 != mReferenceCounter) { atomic_post_inc(mReferenceCounter); } return *this; } template template utils::SharedPtr utils::SharedPtr::static_pointer_cast(const SharedPtr& pointer) { SharedPtr casted_pointer; casted_pointer.mObject = static_cast(pointer.mObject); casted_pointer.mReferenceCounter = pointer.mReferenceCounter; if (0 != casted_pointer.mReferenceCounter) { atomic_post_inc(casted_pointer.mReferenceCounter); } return casted_pointer; } template template utils::SharedPtr utils::SharedPtr::dynamic_pointer_cast(const SharedPtr& pointer) { SharedPtr casted_pointer; casted_pointer.mObject = dynamic_cast(pointer.mObject); if (NULL != casted_pointer.mObject) { casted_pointer.mReferenceCounter = pointer.mReferenceCounter; if (0 != casted_pointer.mReferenceCounter) { atomic_post_inc(casted_pointer.mReferenceCounter); } } return casted_pointer; } template ObjectType* utils::SharedPtr::operator->() const { DCHECK(mObject); return mObject; } template ObjectType& utils::SharedPtr::operator*() const { DCHECK(mObject); return *mObject; } template utils::SharedPtr::operator bool() const { return valid(); } template void utils::SharedPtr::reset() { reset_impl(0); } template void utils::SharedPtr::reset(ObjectType* other) { DCHECK(other != NULL); reset_impl(other); } template void SharedPtr::release() { delete mObject; mObject = 0; delete mReferenceCounter; mReferenceCounter = 0; } template void utils::SharedPtr::reset_impl(ObjectType* other) { dropReference(); mObject = other; mReferenceCounter = new uint32_t(1); } template inline void SharedPtr::dropReference() { if (0 != mReferenceCounter) { if (1 == atomic_post_dec(mReferenceCounter)) { release(); } } } template ObjectType* SharedPtr::get() const { return mObject; } template inline bool SharedPtr::valid() const { if (mReferenceCounter && (0 < *mReferenceCounter)) { return (mObject != NULL); } return false; } } // namespace utils #endif // SRC_COMPONENTS_INCLUDE_UTILS_SHARED_PTR_H_ // vim: set ts=2 sw=2 et: