diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7af91b837..e8736b6ff 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -136,6 +136,7 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES object/base-object.h object/clonable-object-p.h object/clonable-object.h + object/clonable-shared-pointer.h object/object-head-p.h object/object-head.h object/object-p.h diff --git a/src/object/clonable-shared-pointer.h b/src/object/clonable-shared-pointer.h new file mode 100644 index 000000000..52c640d5c --- /dev/null +++ b/src/object/clonable-shared-pointer.h @@ -0,0 +1,156 @@ +/* + * clonable-shared-pointer.h + * Copyright (C) 2010-2018 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _L_CLONABLE_SHARED_POINTER_H_ +#define _L_CLONABLE_SHARED_POINTER_H_ + +#include "linphone/utils/general.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class SharedObject { +template +friend class ClonableSharedPointer; + +public: + int getRefCount () { + return mRefCounter; + } + +protected: + SharedObject () : mRefCounter(1) {} + + // Do not use virtual here. Avoid extra storage (little bonus). + ~SharedObject () = default; + +private: + int mRefCounter; + + L_DISABLE_COPY(SharedObject); +}; + +// ----------------------------------------------------------------------------- + +template +class ClonableSharedPointer { + static_assert(std::is_base_of::value, "T must be a inherited class of SharedObject."); + +public: + explicit ClonableSharedPointer (T *pointer = nullptr) : mPointer(pointer) {} + + ClonableSharedPointer (const ClonableSharedPointer &other) : mPointer(other.mPointer) { + ref(); + } + + ClonableSharedPointer (ClonableSharedPointer &&other) : mPointer(other.mPointer) { + other.mPointer = nullptr; + } + + ~ClonableSharedPointer () { + unref(); + } + + ClonableSharedPointer &operator= (const ClonableSharedPointer &other) { + if (mPointer != other.mPointer) { + unref(); + mPointer = other.mPointer; + ref(); + } + return *this; + } + + ClonableSharedPointer &operator= (ClonableSharedPointer &&other) { + std::swap(mPointer, other.mPointer); + return *this; + } + + bool operator== (const ClonableSharedPointer &other) const { + return mPointer == other.mPointer; + } + + bool operator!= (const ClonableSharedPointer &other) const { + return mPointer != other.mPointer; + } + + T &operator* () { + N_ASSERT(mPointer); + tryClone(); + return *mPointer; + } + + const T &operator* () const { + N_ASSERT(mPointer); + return *mPointer; + } + + T *operator-> () { + tryClone(); + return mPointer; + } + + const T *operator-> () const { + return mPointer; + } + + explicit operator bool () const { + return mPointer; + } + + bool operator! () const { + return !mPointer; + } + + T *get () { + return mPointer; + } + + const T *get () const { + return mPointer; + } + +private: + void ref () { + if (mPointer) + ++mPointer->mRefCounter; + } + + void unref () { + if (mPointer && --mPointer->mRefCounter == 0) { + delete mPointer; + mPointer = nullptr; + } + } + + void tryClone () { + if (mPointer && mPointer->mRefCounter > 1) { + T *newPointer = new T(*mPointer); + if (--mPointer->mRefCounter == 0) + delete mPointer; + mPointer = newPointer; + } + } + + T *mPointer; +}; + +LINPHONE_END_NAMESPACE + +#endif // _L_CLONABLE_SHARED_POINTER_H_