387 lines
9.4 KiB
C
387 lines
9.4 KiB
C
|
//-----------------------------------------------------------------------------
|
||
|
// Project : SDK Core
|
||
|
//
|
||
|
// Category : SDK Core Interfaces
|
||
|
// Filename : pluginterfaces/base/smartpointer.h
|
||
|
// Created by : Steinberg, 01/2004
|
||
|
// Description : Basic Interface
|
||
|
//
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// This file is part of a Steinberg SDK. It is subject to the license terms
|
||
|
// in the LICENSE file found in the top-level directory of this distribution
|
||
|
// and at www.steinberg.net/sdklicenses.
|
||
|
// No part of the SDK, including this file, may be copied, modified, propagated,
|
||
|
// or distributed except according to the terms contained in the LICENSE file.
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
#pragma once
|
||
|
|
||
|
#include "pluginterfaces/base/fplatform.h"
|
||
|
#if SMTG_CPP11_STDLIBSUPPORT
|
||
|
#include <utility>
|
||
|
#endif
|
||
|
|
||
|
//------------------------------------------------------------------------
|
||
|
namespace Steinberg {
|
||
|
|
||
|
//------------------------------------------------------------------------
|
||
|
// IPtr
|
||
|
//------------------------------------------------------------------------
|
||
|
/** IPtr - Smart pointer template class.
|
||
|
\ingroup pluginBase
|
||
|
|
||
|
- can be used as an I* pointer
|
||
|
- handles refCount of the interface
|
||
|
- Usage example:
|
||
|
\code
|
||
|
IPtr<IPath> path (sharedPath);
|
||
|
if (path)
|
||
|
path->ascend ();
|
||
|
\endcode
|
||
|
*/
|
||
|
//------------------------------------------------------------------------
|
||
|
template <class I>
|
||
|
class IPtr
|
||
|
{
|
||
|
public:
|
||
|
//------------------------------------------------------------------------
|
||
|
inline IPtr (I* ptr, bool addRef = true);
|
||
|
inline IPtr (const IPtr&);
|
||
|
|
||
|
template <class T>
|
||
|
inline IPtr (const IPtr<T>& other) : ptr (other.get ())
|
||
|
{
|
||
|
if (ptr)
|
||
|
ptr->addRef ();
|
||
|
}
|
||
|
|
||
|
inline IPtr ();
|
||
|
inline ~IPtr ();
|
||
|
|
||
|
inline I* operator= (I* ptr);
|
||
|
|
||
|
inline IPtr& operator= (const IPtr& other);
|
||
|
|
||
|
template <class T>
|
||
|
inline IPtr& operator= (const IPtr<T>& other)
|
||
|
{
|
||
|
operator= (other.get ());
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
inline operator I* () const { return ptr; } // act as I*
|
||
|
inline I* operator-> () const { return ptr; } // act as I*
|
||
|
|
||
|
inline I* get () const { return ptr; }
|
||
|
|
||
|
#if SMTG_CPP11_STDLIBSUPPORT
|
||
|
inline IPtr (IPtr<I>&& movePtr) SMTG_NOEXCEPT : ptr (movePtr.take ()) { }
|
||
|
|
||
|
template <typename T>
|
||
|
inline IPtr (IPtr<T>&& movePtr) SMTG_NOEXCEPT : ptr (movePtr.take ()) { }
|
||
|
|
||
|
inline IPtr& operator= (IPtr<I>&& movePtr)
|
||
|
{
|
||
|
if (ptr)
|
||
|
ptr->release ();
|
||
|
|
||
|
ptr = movePtr.take ();
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
template <typename T>
|
||
|
inline IPtr& operator= (IPtr<T>&& movePtr)
|
||
|
{
|
||
|
if (ptr)
|
||
|
ptr->release ();
|
||
|
|
||
|
ptr = movePtr.take ();
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
inline void reset (I* obj = nullptr)
|
||
|
{
|
||
|
if (ptr)
|
||
|
ptr->release();
|
||
|
ptr = obj;
|
||
|
}
|
||
|
|
||
|
I* take () SMTG_NOEXCEPT
|
||
|
{
|
||
|
I* out = ptr;
|
||
|
ptr = nullptr;
|
||
|
return out;
|
||
|
}
|
||
|
|
||
|
template <typename T>
|
||
|
static IPtr<T> adopt (T* obj) SMTG_NOEXCEPT { return IPtr<T> (obj, false); }
|
||
|
|
||
|
#endif
|
||
|
//------------------------------------------------------------------------
|
||
|
protected:
|
||
|
I* ptr;
|
||
|
};
|
||
|
|
||
|
//------------------------------------------------------------------------
|
||
|
template <class I>
|
||
|
inline IPtr<I>::IPtr (I* _ptr, bool addRef) : ptr (_ptr)
|
||
|
{
|
||
|
if (ptr && addRef)
|
||
|
ptr->addRef ();
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------
|
||
|
template <class I>
|
||
|
inline IPtr<I>::IPtr (const IPtr<I>& other) : ptr (other.ptr)
|
||
|
{
|
||
|
if (ptr)
|
||
|
ptr->addRef ();
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------
|
||
|
template <class I>
|
||
|
inline IPtr<I>::IPtr () : ptr (0)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------
|
||
|
template <class I>
|
||
|
inline IPtr<I>::~IPtr ()
|
||
|
{
|
||
|
if (ptr)
|
||
|
{
|
||
|
ptr->release ();
|
||
|
ptr = nullptr; //TODO_CORE: how much does this cost? is this something hiding for us?
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------
|
||
|
template <class I>
|
||
|
inline I* IPtr<I>::operator= (I* _ptr)
|
||
|
{
|
||
|
if (_ptr != ptr)
|
||
|
{
|
||
|
if (ptr)
|
||
|
ptr->release ();
|
||
|
ptr = _ptr;
|
||
|
if (ptr)
|
||
|
ptr->addRef ();
|
||
|
}
|
||
|
return ptr;
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------
|
||
|
template <class I>
|
||
|
inline IPtr<I>& IPtr<I>::operator= (const IPtr<I>& _ptr)
|
||
|
{
|
||
|
operator= (_ptr.ptr);
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------
|
||
|
/** OPtr - "owning" smart pointer used for newly created FObjects.
|
||
|
\ingroup pluginBase
|
||
|
|
||
|
FUnknown implementations are supposed to have a refCount of 1 right after creation.
|
||
|
So using an IPtr on newly created objects would lead to a leak.
|
||
|
Instead the OPtr can be used in this case. \n
|
||
|
Example:
|
||
|
\code
|
||
|
OPtr<IPath> path = FHostCreate (IPath, hostClasses);
|
||
|
// no release is needed...
|
||
|
\endcode
|
||
|
The assignment operator takes ownership of a new object and releases the old.
|
||
|
So its safe to write:
|
||
|
\code
|
||
|
OPtr<IPath> path = FHostCreate (IPath, hostClasses);
|
||
|
path = FHostCreate (IPath, hostClasses);
|
||
|
path = 0;
|
||
|
\endcode
|
||
|
This is the difference to using an IPtr with addRef=false.
|
||
|
\code
|
||
|
// DONT DO THIS:
|
||
|
IPtr<IPath> path (FHostCreate (IPath, hostClasses), false);
|
||
|
path = FHostCreate (IPath, hostClasses);
|
||
|
path = 0;
|
||
|
\endcode
|
||
|
This will lead to a leak!
|
||
|
*/
|
||
|
//------------------------------------------------------------------------
|
||
|
template <class I>
|
||
|
class OPtr : public IPtr<I>
|
||
|
{
|
||
|
public:
|
||
|
//------------------------------------------------------------------------
|
||
|
inline OPtr (I* p) : IPtr<I> (p, false) {}
|
||
|
inline OPtr (const IPtr<I>& p) : IPtr<I> (p) {}
|
||
|
inline OPtr (const OPtr<I>& p) : IPtr<I> (p) {}
|
||
|
inline OPtr () {}
|
||
|
inline I* operator= (I* _ptr)
|
||
|
{
|
||
|
if (_ptr != this->ptr)
|
||
|
{
|
||
|
if (this->ptr)
|
||
|
this->ptr->release ();
|
||
|
this->ptr = _ptr;
|
||
|
}
|
||
|
return this->ptr;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
//------------------------------------------------------------------------
|
||
|
/** Assigning newly created object to an IPtr.
|
||
|
Example:
|
||
|
\code
|
||
|
IPtr<IPath> path = owned (FHostCreate (IPath, hostClasses));
|
||
|
\endcode
|
||
|
which is a slightly shorter form of writing:
|
||
|
\code
|
||
|
IPtr<IPath> path = OPtr<IPath> (FHostCreate (IPath, hostClasses));
|
||
|
\endcode
|
||
|
*/
|
||
|
template <class I>
|
||
|
IPtr<I> owned (I* p)
|
||
|
{
|
||
|
return IPtr<I> (p, false);
|
||
|
}
|
||
|
|
||
|
/** Assigning shared object to an IPtr.
|
||
|
Example:
|
||
|
\code
|
||
|
IPtr<IPath> path = shared (iface.getXY ());
|
||
|
\endcode
|
||
|
*/
|
||
|
template <class I>
|
||
|
IPtr<I> shared (I* p)
|
||
|
{
|
||
|
return IPtr<I> (p, true);
|
||
|
}
|
||
|
|
||
|
#if SMTG_CPP11_STDLIBSUPPORT
|
||
|
//------------------------------------------------------------------------
|
||
|
// Ownership functionality
|
||
|
//------------------------------------------------------------------------
|
||
|
namespace SKI {
|
||
|
namespace Detail {
|
||
|
struct Adopt;
|
||
|
} // Detail
|
||
|
|
||
|
/** Strong typedef for shared reference counted objects.
|
||
|
* Use SKI::adopt to unwrap the provided object.
|
||
|
* @tparam T Referenced counted type.
|
||
|
*/
|
||
|
template <typename T>
|
||
|
class Shared
|
||
|
{
|
||
|
friend struct Detail::Adopt;
|
||
|
T* obj = nullptr;
|
||
|
};
|
||
|
|
||
|
/** Strong typedef for transferring the ownership of reference counted objects.
|
||
|
* Use SKI::adopt to unwrap the provided object.
|
||
|
* After calling adopt the reference in this object is null.
|
||
|
* @tparam T Referenced counted type.
|
||
|
*/
|
||
|
template <typename T>
|
||
|
class Owned
|
||
|
{
|
||
|
friend struct Detail::Adopt;
|
||
|
T* obj = nullptr;
|
||
|
};
|
||
|
|
||
|
/** Strong typedef for using reference counted objects.
|
||
|
* Use SKI::adopt to unwrap the provided object.
|
||
|
* After calling adopt the reference in this object is null.
|
||
|
* @tparam T Referenced counted type.
|
||
|
*/
|
||
|
template <typename T>
|
||
|
class Used
|
||
|
{
|
||
|
friend struct Detail::Adopt;
|
||
|
T* obj = nullptr;
|
||
|
};
|
||
|
|
||
|
namespace Detail {
|
||
|
|
||
|
struct Adopt
|
||
|
{
|
||
|
template <typename T>
|
||
|
static IPtr<T> adopt (Shared<T>& ref)
|
||
|
{
|
||
|
using Steinberg::shared;
|
||
|
return shared (ref.obj);
|
||
|
}
|
||
|
|
||
|
template <typename T>
|
||
|
static IPtr<T> adopt (Owned<T>& ref)
|
||
|
{
|
||
|
using Steinberg::owned;
|
||
|
IPtr<T> out = owned (ref.obj);
|
||
|
ref.obj = nullptr;
|
||
|
return out;
|
||
|
}
|
||
|
|
||
|
template <typename T>
|
||
|
static T* adopt (Used<T>& ref)
|
||
|
{
|
||
|
return ref.obj;
|
||
|
}
|
||
|
|
||
|
template <template <typename> class OwnerType, typename T>
|
||
|
static OwnerType<T> toOwnerType (T* obj)
|
||
|
{
|
||
|
OwnerType<T> out;
|
||
|
out.obj = obj;
|
||
|
return out;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
} // Detail
|
||
|
|
||
|
/** Common function to adopt referenced counted object.
|
||
|
* @tparam T Referenced counted type.
|
||
|
* @param ref The reference to be adopted in a smart pointer.
|
||
|
*/
|
||
|
template <typename T>
|
||
|
IPtr<T> adopt (Shared<T>& ref) { return Detail::Adopt::adopt (ref); }
|
||
|
|
||
|
template <typename T>
|
||
|
IPtr<T> adopt (Shared<T>&& ref) { return Detail::Adopt::adopt (ref); }
|
||
|
|
||
|
/** Common function to adopt referenced counted object.
|
||
|
* @tparam T Referenced counted type.
|
||
|
* @param ref The reference to be adopted in a smart pointer.
|
||
|
*/
|
||
|
template <typename T>
|
||
|
IPtr<T> adopt (Owned<T>& ref) { return Detail::Adopt::adopt (ref); }
|
||
|
|
||
|
template <typename T>
|
||
|
IPtr<T> adopt (Owned<T>&& ref) { return Detail::Adopt::adopt (ref); }
|
||
|
|
||
|
/** Common function to adopt referenced counted object.
|
||
|
* @tparam T Referenced counted type.
|
||
|
* @param ref The reference to be adopted in a smart pointer.
|
||
|
*/
|
||
|
template <typename T>
|
||
|
T* adopt (Used<T>& ref) { return Detail::Adopt::adopt (ref); }
|
||
|
|
||
|
template <typename T>
|
||
|
T* adopt (Used<T>&& ref) { return Detail::Adopt::adopt (ref); }
|
||
|
|
||
|
/** Common function to wrap owned instances. */
|
||
|
template <typename T>
|
||
|
Owned<T> toOwned (T* obj) { return Detail::Adopt::toOwnerType<Owned> (obj); }
|
||
|
|
||
|
/** Common function to wrap shared instances. */
|
||
|
template <typename T>
|
||
|
Shared<T> toShared (T* obj) { return Detail::Adopt::toOwnerType<Shared> (obj); }
|
||
|
|
||
|
/** Common function to wrap used instances. */
|
||
|
template <typename T>
|
||
|
Used<T> toUsed (T* obj) { return Detail::Adopt::toOwnerType<Used> (obj); }
|
||
|
|
||
|
//------------------------------------------------------------------------
|
||
|
} // SKI
|
||
|
#endif
|
||
|
} // Steinberg
|