|
- //------------------------------------------------------------------------
- // Project : SDK Base
- // Version : 1.0
- //
- // Category : Helpers
- // Filename : base/source/fobject.h
- // Created by : Steinberg, 2008
- // Description : Basic Object implementing FUnknown
- //
- //-----------------------------------------------------------------------------
- // LICENSE
- // (c) 2019, Steinberg Media Technologies GmbH, 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 Steinberg Media Technologies 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 OWNER 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.
- //-----------------------------------------------------------------------------
-
- //------------------------------------------------------------------------
- /** @file base/source/fobject.h
- Basic Object implementing FUnknown. */
- //------------------------------------------------------------------------
- #pragma once
-
- #include "pluginterfaces/base/funknown.h"
- #include "pluginterfaces/base/iupdatehandler.h"
- //#include "base/source/basefwd.h"
- #include "base/source/fdebug.h" // NEW
-
-
- namespace Steinberg {
-
- //----------------------------------
-
- typedef FIDString FClassID;
-
- //------------------------------------------------------------------------
- // Basic FObject - implements FUnknown + IDependent
- //------------------------------------------------------------------------
- /** Implements FUnknown and IDependent.
-
- FObject is a polymorphic class that implements IDependent (of SKI module)
- and therefore derived from FUnknown, which is the most abstract base class of all.
-
- All COM-like virtual methods of FUnknown such as queryInterface(), addRef(), release()
- are implemented here. On top of that, dependency-related methods are implemented too.
-
- Pointer casting is done via the template methods FCast, either FObject to FObject or
- FUnknown to FObject.
-
- FObject supports a new singleton concept, therefore these objects are deleted automatically upon program termination.
-
- - Runtime type information: An object can be queried at runtime, of what class
- it is. To do this correctly, every class must override some methods. This
- is simplified by using the OBJ_METHODS macros
-
-
- @see
- - FUnknown
- - IDependent
- - IUpdateHandler
- */
- //------------------------------------------------------------------------
- class FObject : public IDependent
- {
- public:
- //------------------------------------------------------------------------
- FObject () : refCount (1) {} ///< default constructor...
- FObject (const FObject&) : refCount (1) {} ///< overloaded constructor...
- virtual ~FObject () {} ///< destructor...
- FObject& operator = (const FObject&) { return *this; } ///< overloads operator "=" as the reference assignment
-
- // OBJECT_METHODS
- static inline FClassID getFClassID () {return "FObject";} ///< return Class ID as an ASCII string (statically)
- virtual FClassID isA () const {return FObject::getFClassID ();} ///< a local alternative to getFClassID ()
- virtual bool isA (FClassID s) const {return isTypeOf (s, false);} ///< evaluates if the passed ID is of the FObject type
- virtual bool isTypeOf (FClassID s, bool /*askBaseClass*/ = true) const {return classIDsEqual (s, FObject::getFClassID ());}
- ///< evaluates if the passed ID is of the FObject type
- int32 getRefCount () {return refCount;} ///< returns the current interface reference count
- FUnknown* unknownCast () {return this;} ///< get FUnknown interface from object
-
- // FUnknown
- virtual tresult PLUGIN_API queryInterface (const TUID _iid, void** obj) SMTG_OVERRIDE; ///< please refer to FUnknown::queryInterface ()
- virtual uint32 PLUGIN_API addRef () SMTG_OVERRIDE; ///< please refer to FUnknown::addref ()
- virtual uint32 PLUGIN_API release () SMTG_OVERRIDE; ///< please refer to FUnknown::release ()
-
- // IDependent
- virtual void PLUGIN_API update (FUnknown* /*changedUnknown*/, int32 /*message*/) SMTG_OVERRIDE {}
- ///< empty virtual method that should be overridden by derived classes for data updates upon changes
- // IDependency
- virtual void addDependent (IDependent* dep); ///< adds dependency to the object
- virtual void removeDependent (IDependent* dep); ///< removes dependency from the object
- virtual void changed (int32 msg = kChanged); ///< Inform all dependents, that the object has changed.
- virtual void deferUpdate (int32 msg = kChanged); ///< Similar to triggerUpdates, except only delivered in idle (usefull in collecting updates).
- virtual void updateDone (int32 /* msg */) {} ///< empty virtual method that should be overridden by derived classes
- virtual bool isEqualInstance (FUnknown* d) {return this == d;}
-
- static void setUpdateHandler (IUpdateHandler* handler) {gUpdateHandler = handler;} ///< set method for the local attribute
- static IUpdateHandler* getUpdateHandler () {return gUpdateHandler;} ///< get method for the local attribute
-
- // static helper functions
- static inline bool classIDsEqual (FClassID ci1, FClassID ci2); ///< compares (evaluates) 2 class IDs
- static inline FObject* unknownToObject (FUnknown* unknown); ///< pointer conversion from FUnknown to FObject
-
- /** Special UID that is used to cast an FUnknown pointer to a FObject */
- static const FUID iid;
-
- //------------------------------------------------------------------------
- protected:
- int32 refCount; ///< COM-model local reference count
-
- static IUpdateHandler* gUpdateHandler;
- };
-
-
- //------------------------------------------------------------------------
- // conversion from FUnknown to FObject
- //------------------------------------------------------------------------
- inline FObject* FObject::unknownToObject (FUnknown* unknown)
- {
- FObject* object = 0;
- if (unknown)
- {
- unknown->queryInterface (FObject::iid, (void**)&object);
- if (object)
- object->release (); // queryInterface has added ref
- }
- return object;
- }
-
- //------------------------------------------------------------------------
- inline bool FObject::classIDsEqual (FClassID ci1, FClassID ci2)
- {
- return (ci1 && ci2) ? (strcmp (ci1, ci2) == 0) : false;
- }
-
- //-----------------------------------------------------------------------
- /** FCast overload 1 - FObject to FObject */
- //-----------------------------------------------------------------------
- template <class C>
- inline C* FCast (const FObject* object)
- {
- if (object && object->isTypeOf (C::getFClassID (), true))
- return (C*) object;
- return 0;
- }
-
- //-----------------------------------------------------------------------
- /** FCast overload 2 - FUnknown to FObject */
- //-----------------------------------------------------------------------
- template <class C>
- inline C* FCast (FUnknown* unknown)
- {
- FObject* object = FObject::unknownToObject (unknown);
- return FCast<C> (object);
- }
-
- //-----------------------------------------------------------------------
- /** FUCast - casting from FUnknown to Interface */
- //-----------------------------------------------------------------------
- template <class C>
- inline C* FUCast (FObject* object)
- {
- return FUnknownPtr<C> (object ? object->unknownCast () : 0);
- }
-
- template <class C>
- inline C* FUCast (FUnknown* object)
- {
- return FUnknownPtr<C> (object);
- }
-
- //------------------------------------------------------------------------
- /** @name Convenience methods that call release or delete respectively
- on a pointer if it is non-zero, and then set the pointer to zero.
- Note: you should prefer using IPtr or OPtr instead of these methods
- whenever possible.
- <b>Examples:</b>
- @code
- ~Foo ()
- {
- // instead of ...
- if (somePointer)
- {
- somePointer->release ();
- somePointer = 0;
- }
- // ... just being lazy I write
- SafeRelease (somePointer)
- }
- @endcode
- */
- ///@{
- //-----------------------------------------------------------------------
- template <class I>
- inline void SafeRelease (I *& ptr)
- {
- if (ptr)
- {
- ptr->release ();
- ptr = 0;
- }
- }
-
- //-----------------------------------------------------------------------
- template <class I>
- inline void SafeRelease (IPtr<I> & ptr)
- {
- ptr = 0;
- }
-
-
- //-----------------------------------------------------------------------
- template <class T>
- inline void SafeDelete (T *& ptr)
- {
- if (ptr)
- {
- delete ptr;
- ptr = 0;
- }
- }
- ///@}
-
- //-----------------------------------------------------------------------
- template <class T>
- inline void AssignShared (T*& dest, T* newPtr)
- {
- if (dest == newPtr)
- return;
-
- if (dest)
- dest->release ();
- dest = newPtr;
- if (dest)
- dest->addRef ();
- }
-
- //-----------------------------------------------------------------------
- template <class T>
- inline void AssignSharedDependent (IDependent* _this, T*& dest, T* newPtr)
- {
- if (dest == newPtr)
- return;
-
- if (dest)
- dest->removeDependent (_this);
- AssignShared (dest, newPtr);
- if (dest)
- dest->addDependent (_this);
- }
-
- //-----------------------------------------------------------------------
- template <class T>
- inline void AssignSharedDependent (IDependent* _this, IPtr<T>& dest, T* newPtr)
- {
- if (dest == newPtr)
- return;
-
- if (dest)
- dest->removeDependent (_this);
- dest = newPtr;
- if (dest)
- dest->addDependent (_this);
- }
-
- //-----------------------------------------------------------------------
- template <class T>
- inline void SafeReleaseDependent (IDependent* _this, T*& dest)
- {
- if (dest)
- dest->removeDependent (_this);
- SafeRelease (dest);
- }
-
- //-----------------------------------------------------------------------
- template <class T>
- inline void SafeReleaseDependent (IDependent* _this, IPtr<T>& dest)
- {
- if (dest)
- dest->removeDependent (_this);
- SafeRelease (dest);
- }
-
-
- //------------------------------------------------------------------------
- /** Automatic creation and destruction of singleton instances. */
- namespace Singleton {
- /** registers an instance (type FObject) */
- void registerInstance (FObject** o);
-
- /** Returns true when singleton instances were already released. */
- bool isTerminated ();
-
- /** lock and unlock the singleton registration for multi-threading safety */
- void lockRegister ();
- void unlockRegister ();
- }
-
- //------------------------------------------------------------------------
- } // namespace Steinberg
-
- //-----------------------------------------------------------------------
- #define SINGLETON(ClassName) \
- static ClassName* instance (bool create = true) \
- { \
- static Steinberg::FObject* inst = nullptr; \
- if (inst == nullptr && create && Steinberg::Singleton::isTerminated () == false) \
- { \
- Steinberg::Singleton::lockRegister (); \
- if (inst == nullptr) \
- { \
- inst = NEW ClassName; \
- Steinberg::Singleton::registerInstance (&inst); \
- } \
- Steinberg::Singleton::unlockRegister (); \
- } \
- return (ClassName*)inst; \
- }
-
- //-----------------------------------------------------------------------
- #define OBJ_METHODS(className, baseClass) \
- static inline Steinberg::FClassID getFClassID () {return (#className);} \
- virtual Steinberg::FClassID isA () const SMTG_OVERRIDE {return className::getFClassID ();} \
- virtual bool isA (Steinberg::FClassID s) const SMTG_OVERRIDE {return isTypeOf (s, false);} \
- virtual bool isTypeOf (Steinberg::FClassID s, bool askBaseClass = true) const SMTG_OVERRIDE \
- { return (classIDsEqual (s, #className) ? true : (askBaseClass ? baseClass::isTypeOf (s, true) : false)); }
-
- //------------------------------------------------------------------------
- /** Delegate refcount functions to BaseClass.
- BaseClase must implement ref counting.
- */
- //------------------------------------------------------------------------
- #define REFCOUNT_METHODS(BaseClass) \
- virtual Steinberg::uint32 PLUGIN_API addRef ()SMTG_OVERRIDE{ return BaseClass::addRef (); } \
- virtual Steinberg::uint32 PLUGIN_API release ()SMTG_OVERRIDE{ return BaseClass::release (); }
-
- //------------------------------------------------------------------------
- /** @name Macros to implement FUnknown::queryInterface ().
-
- <b>Examples:</b>
- @code
- class Foo : public FObject, public IFoo2, public IFoo3
- {
- ...
- DEFINE_INTERFACES
- DEF_INTERFACE (IFoo2)
- DEF_INTERFACE (IFoo3)
- END_DEFINE_INTERFACES (FObject)
- REFCOUNT_METHODS(FObject)
- // Implement IFoo2 interface ...
- // Implement IFoo3 interface ...
- ...
- };
- @endcode
- */
- ///@{
- //------------------------------------------------------------------------
- /** Start defining interfaces. */
- //------------------------------------------------------------------------
- #define DEFINE_INTERFACES \
- Steinberg::tresult PLUGIN_API queryInterface (const Steinberg::TUID iid, void** obj) SMTG_OVERRIDE \
- {
-
- //------------------------------------------------------------------------
- /** Add a interfaces. */
- //------------------------------------------------------------------------
- #define DEF_INTERFACE(InterfaceName) \
- QUERY_INTERFACE (iid, obj, InterfaceName::iid, InterfaceName)
-
- //------------------------------------------------------------------------
- /** End defining interfaces. */
- //------------------------------------------------------------------------
- #define END_DEFINE_INTERFACES(BaseClass) \
- return BaseClass::queryInterface (iid, obj); \
- }
- ///@}
-
- //------------------------------------------------------------------------
- /** @name Convenient macros to implement Steinberg::FUnknown::queryInterface ().
- <b>Examples:</b>
- @code
- class Foo : public FObject, public IFoo2, public IFoo3
- {
- ...
- DEF_INTERFACES_2(IFoo2,IFoo3,FObject)
- REFCOUNT_METHODS(FObject)
- ...
- };
- @endcode
- */
- ///@{
- //------------------------------------------------------------------------
- #define DEF_INTERFACES_1(InterfaceName,BaseClass) \
- DEFINE_INTERFACES \
- DEF_INTERFACE (InterfaceName) \
- END_DEFINE_INTERFACES (BaseClass)
-
- //------------------------------------------------------------------------
- #define DEF_INTERFACES_2(InterfaceName1,InterfaceName2,BaseClass) \
- DEFINE_INTERFACES \
- DEF_INTERFACE (InterfaceName1) \
- DEF_INTERFACE (InterfaceName2) \
- END_DEFINE_INTERFACES (BaseClass)
-
- //------------------------------------------------------------------------
- #define DEF_INTERFACES_3(InterfaceName1,InterfaceName2,InterfaceName3,BaseClass) \
- DEFINE_INTERFACES \
- DEF_INTERFACE (InterfaceName1) \
- DEF_INTERFACE (InterfaceName2) \
- DEF_INTERFACE (InterfaceName3) \
- END_DEFINE_INTERFACES (BaseClass)
-
- //------------------------------------------------------------------------
- #define DEF_INTERFACES_4(InterfaceName1,InterfaceName2,InterfaceName3,InterfaceName4,BaseClass) \
- DEFINE_INTERFACES \
- DEF_INTERFACE (InterfaceName1) \
- DEF_INTERFACE (InterfaceName2) \
- DEF_INTERFACE (InterfaceName3) \
- DEF_INTERFACE (InterfaceName4) \
- END_DEFINE_INTERFACES (BaseClass)
- ///@}
-
- //------------------------------------------------------------------------
- /** @name Convenient macros to implement Steinberg::FUnknown methods.
- <b>Examples:</b>
- @code
- class Foo : public FObject, public IFoo2, public IFoo3
- {
- ...
- FUNKNOWN_METHODS2(IFoo2,IFoo3,FObject)
- ...
- };
- @endcode
- */
- ///@{
- #define FUNKNOWN_METHODS(InterfaceName,BaseClass) \
- DEF_INTERFACES_1(InterfaceName,BaseClass) \
- REFCOUNT_METHODS(BaseClass)
-
- #define FUNKNOWN_METHODS2(InterfaceName1,InterfaceName2,BaseClass) \
- DEF_INTERFACES_2(InterfaceName1,InterfaceName2,BaseClass) \
- REFCOUNT_METHODS(BaseClass)
-
- #define FUNKNOWN_METHODS3(InterfaceName1,InterfaceName2,InterfaceName3,BaseClass) \
- DEF_INTERFACES_3(InterfaceName1,InterfaceName2,InterfaceName3,BaseClass) \
- REFCOUNT_METHODS(BaseClass)
-
- #define FUNKNOWN_METHODS4(InterfaceName1,InterfaceName2,InterfaceName3,InterfaceName4,BaseClass) \
- DEF_INTERFACES_4(InterfaceName1,InterfaceName2,InterfaceName3,InterfaceName4,BaseClass) \
- REFCOUNT_METHODS(BaseClass)
- ///@}
-
-
- //------------------------------------------------------------------------
- //------------------------------------------------------------------------
- #if COM_COMPATIBLE
- //------------------------------------------------------------------------
- /** @name Macros to implement IUnknown interfaces with FObject.
- <b>Examples:</b>
- @code
- class MyEnumFormat : public FObject, IEnumFORMATETC
- {
- ...
- COM_UNKNOWN_METHODS (IEnumFORMATETC, IUnknown)
- ...
- };
- @endcode
- */
- ///@{
- //------------------------------------------------------------------------
- #define IUNKNOWN_REFCOUNT_METHODS(BaseClass) \
- STDMETHOD_ (ULONG, AddRef) (void) {return BaseClass::addRef ();} \
- STDMETHOD_ (ULONG, Release) (void) {return BaseClass::release ();}
-
- //------------------------------------------------------------------------
- #define COM_QUERY_INTERFACE(iid, obj, InterfaceName) \
- if (riid == __uuidof(InterfaceName)) \
- { \
- addRef (); \
- *obj = (InterfaceName*)this; \
- return kResultOk; \
- }
-
- //------------------------------------------------------------------------
- #define COM_OBJECT_QUERY_INTERFACE(InterfaceName,BaseClass) \
- STDMETHOD (QueryInterface) (REFIID riid, void** object) \
- { \
- COM_QUERY_INTERFACE (riid, object, InterfaceName) \
- return BaseClass::queryInterface ((FIDString)&riid, object); \
- }
-
- //------------------------------------------------------------------------
- #define COM_UNKNOWN_METHODS(InterfaceName,BaseClass) \
- COM_OBJECT_QUERY_INTERFACE(InterfaceName,BaseClass) \
- IUNKNOWN_REFCOUNT_METHODS(BaseClass)
- ///@}
-
- #endif // COM_COMPATIBLE
|