/**************************************************************************************/ /* */ /* Visualization Library */ /* http://visualizationlibrary.org */ /* */ /* Copyright (c) 2005-2020, Michele Bosi */ /* 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. */ /* */ /* 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 Object_INCLUDE_ONCE #define Object_INCLUDE_ONCE #include #include #include #include #if VL_DEBUG_LIVING_OBJECTS #include #endif namespace vl { //------------------------------------------------------------------------------ // ref //------------------------------------------------------------------------------ /** * The ref<> class is used to reference-count an Object. * When the last ref<> that points to an Object is deallocated also the pointed Object is deallocated. * @note IMPORTANT: assigning to a ref<> 'washes aways' the constness of an object. */ template class ref { public: // 'const' is required as the copy constructor must have this signature. ref(const ref& other) { mObject = NULL; *this = other; } ref(const T* object=NULL) { mObject = const_cast(object); if (mObject) mObject->incReference(); } template ref(const ref& other) { mObject = NULL; *this = other; } ~ref() { if (mObject) mObject->decReference(); mObject = NULL; } // 'const' is required because operator= must have this signature. ref& operator=(const ref& other) { if (other) other->incReference(); if (mObject) mObject->decReference(); mObject = const_cast(other.get()); return *this; } // 'const' is required because operator= must have this signature. ref& operator=(const T* other) { if (other) other->incReference(); if (mObject) mObject->decReference(); mObject = const_cast(other); return *this; } // 'const' is required because operator= must have this signature. template ref& operator=(const ref& other) { if (other) other->incReference(); if (mObject) mObject->decReference(); mObject = const_cast(other.get()); return *this; } void swap(ref& other) { T* tmp = other.mObject; other = mObject; mObject = tmp; } //! This is mainly useful when using ref<> with std::map, std::set, etc. T* get_writable() const { return mObject; } const T* get() const { return mObject; } const T* operator->() const { VL_CHECK(mObject); return mObject; } const T& operator*() const { VL_CHECK(mObject); return *mObject; } T* get() { return mObject; } T* operator->() { VL_CHECK(mObject); return mObject; } T& operator*() { VL_CHECK(mObject); return *mObject; } bool operator<(const ref& other) const { return mObject < other.mObject; } operator bool() const { return mObject != NULL; } protected: T* mObject; }; // interaction with the other types template inline bool operator==(const ref & o1, const ref & o2) { return o1.get() == o2.get(); } template inline bool operator!=(const ref & o1, const ref & o2) { return o1.get() != o2.get(); } template inline bool operator==(const ref & o1, T2 * o2) { return o1.get() == o2; } template inline bool operator!=(const ref & o1, T2 * o2) { return o1.get() != o2; } template inline bool operator==(T1 * o1, const ref & o2) { return o1 == o2.get(); } template inline bool operator!=(T1 * o1, const ref & o2) { return o1 != o2.get(); } //------------------------------------------------------------------------------ // Object //------------------------------------------------------------------------------ /** * The base class for all the reference counted objects. * See also vl::ref. */ class VLCORE_EXPORT Object { VL_INSTRUMENT_BASE_CLASS(vl::Object) public: //! Constructor. Object() { VL_DEBUG_SET_OBJECT_NAME() mRefCountMutex = NULL; mReferenceCount = 0; mAutomaticDelete = true; // user data #ifdef VL_USER_DATA_OBJECT mUserData = NULL; #endif #if VL_DEBUG_LIVING_OBJECTS debug_living_objects()->insert(this); // mDebug_LivingObjects.insert(this); #endif } //! Copy constructor: copies the name, ref count mutex and user data. Object(const Object& other) { // copy the name, the ref count mutex and the user data. mObjectName = other.mObjectName; mRefCountMutex = other.mRefCountMutex; #ifdef VL_USER_DATA_OBJECT mUserData = other.mUserData; #endif // mReferenceCount and mAutomaticDelete are not copiable. mReferenceCount = 0; mAutomaticDelete = true; // debug living object #if VL_DEBUG_LIVING_OBJECTS debug_living_objects()->insert(this); #endif } //! Copy operator: copies the object's name, ref count mutex and user data. Object& operator=(const Object& other) { // copy the name, the ref count mutex and the user data. mObjectName = other.mObjectName; mRefCountMutex = other.mRefCountMutex; #ifdef VL_USER_DATA_OBJECT mUserData = other.mUserData; #endif // mReferenceCount and mAutomaticDelete are not copiable. // ... return *this; } //! The name of the object, by default set to the object's class name. const std::string& objectName() const { return mObjectName; } //! The name of the object, by default set to the object's class name in debug builds. void setObjectName(const char* name) { mObjectName = name; } //! The name of the object, by default set to the object's class name in debug builds. void setObjectName(const std::string& name) { mObjectName = name; } //! The mutex used to protect the reference counting of an Object across multiple threads. void setRefCountMutex(IMutex* mutex) { mRefCountMutex = mutex; } //! The mutex used to protect the reference counting of an Object across multiple threads. IMutex* refCountMutex() { return mRefCountMutex; } //! The mutex used to protect the reference counting of an Object across multiple threads. const IMutex* refCountMutex() const { return mRefCountMutex; } //! Returns the number of references of an object. int referenceCount() const { return mReferenceCount; } //! Increments the reference count of an object. void incReference() const { // Lock mutex if (refCountMutex()) const_cast(refCountMutex())->lock(); ++mReferenceCount; // Unlock mutex if(refCountMutex()) const_cast(refCountMutex())->unlock(); } //! Decrements the reference count of an object and deletes it if both automaticDelete() is \p true the count reaches 0. void decReference() { // Save local copy in case of deletion. IMutex* mutex = mRefCountMutex; // Lock mutex. if (mutex) mutex->lock(); VL_CHECK(mReferenceCount) --mReferenceCount; if (mReferenceCount == 0 && automaticDelete()) delete this; // Unlock mutex. if (mutex) mutex->unlock(); } //! If set to true the Object is deleted when its reference count reaches 0 void setAutomaticDelete(bool autodel_on) { mAutomaticDelete = autodel_on; } //! If set to true the Object is deleted when its reference count reaches 0 bool automaticDelete() const { return mAutomaticDelete; } //! Casts an Object to the specified class. template T* as() { return cast(this); } //! Casts an Object to the specified class. template const T* as() const { return cast(this); } #ifdef VL_USER_DATA_OBJECT public: const Object* userData() const { return mUserData.get(); } Object* userData() { return mUserData.get(); } void setUserData(Object* user_data) { mUserData = user_data; } private: ref mUserData; #endif protected: virtual ~Object(); std::string mObjectName; IMutex* mRefCountMutex; mutable int mReferenceCount; bool mAutomaticDelete; // debugging facilities public: #if VL_DEBUG_LIVING_OBJECTS static std::set< Object* >* mDebug_LivingObjects; static std::set< Object* >* debug_living_objects() { if (!mDebug_LivingObjects) mDebug_LivingObjects = new std::set< Object* >; return mDebug_LivingObjects; } #endif }; } #endif