Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

519 lines
19KB

  1. //------------------------------------------------------------------------
  2. // Project : SDK Base
  3. // Version : 1.0
  4. //
  5. // Category : Helpers
  6. // Filename : base/source/fobject.h
  7. // Created by : Steinberg, 2008
  8. // Description : Basic Object implementing FUnknown
  9. //
  10. //-----------------------------------------------------------------------------
  11. // LICENSE
  12. // (c) 2019, Steinberg Media Technologies GmbH, All Rights Reserved
  13. //-----------------------------------------------------------------------------
  14. // Redistribution and use in source and binary forms, with or without modification,
  15. // are permitted provided that the following conditions are met:
  16. //
  17. // * Redistributions of source code must retain the above copyright notice,
  18. // this list of conditions and the following disclaimer.
  19. // * Redistributions in binary form must reproduce the above copyright notice,
  20. // this list of conditions and the following disclaimer in the documentation
  21. // and/or other materials provided with the distribution.
  22. // * Neither the name of the Steinberg Media Technologies nor the names of its
  23. // contributors may be used to endorse or promote products derived from this
  24. // software without specific prior written permission.
  25. //
  26. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  27. // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  28. // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  29. // IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
  30. // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  31. // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  32. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  33. // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
  34. // OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  35. // OF THE POSSIBILITY OF SUCH DAMAGE.
  36. //-----------------------------------------------------------------------------
  37. //------------------------------------------------------------------------
  38. /** @file base/source/fobject.h
  39. Basic Object implementing FUnknown. */
  40. //------------------------------------------------------------------------
  41. #pragma once
  42. #include "pluginterfaces/base/funknown.h"
  43. #include "pluginterfaces/base/iupdatehandler.h"
  44. //#include "base/source/basefwd.h"
  45. #include "base/source/fdebug.h" // NEW
  46. namespace Steinberg {
  47. //----------------------------------
  48. typedef FIDString FClassID;
  49. //------------------------------------------------------------------------
  50. // Basic FObject - implements FUnknown + IDependent
  51. //------------------------------------------------------------------------
  52. /** Implements FUnknown and IDependent.
  53. FObject is a polymorphic class that implements IDependent (of SKI module)
  54. and therefore derived from FUnknown, which is the most abstract base class of all.
  55. All COM-like virtual methods of FUnknown such as queryInterface(), addRef(), release()
  56. are implemented here. On top of that, dependency-related methods are implemented too.
  57. Pointer casting is done via the template methods FCast, either FObject to FObject or
  58. FUnknown to FObject.
  59. FObject supports a new singleton concept, therefore these objects are deleted automatically upon program termination.
  60. - Runtime type information: An object can be queried at runtime, of what class
  61. it is. To do this correctly, every class must override some methods. This
  62. is simplified by using the OBJ_METHODS macros
  63. @see
  64. - FUnknown
  65. - IDependent
  66. - IUpdateHandler
  67. */
  68. //------------------------------------------------------------------------
  69. class FObject : public IDependent
  70. {
  71. public:
  72. //------------------------------------------------------------------------
  73. FObject () : refCount (1) {} ///< default constructor...
  74. FObject (const FObject&) : refCount (1) {} ///< overloaded constructor...
  75. virtual ~FObject () {} ///< destructor...
  76. FObject& operator = (const FObject&) { return *this; } ///< overloads operator "=" as the reference assignment
  77. // OBJECT_METHODS
  78. static inline FClassID getFClassID () {return "FObject";} ///< return Class ID as an ASCII string (statically)
  79. virtual FClassID isA () const {return FObject::getFClassID ();} ///< a local alternative to getFClassID ()
  80. virtual bool isA (FClassID s) const {return isTypeOf (s, false);} ///< evaluates if the passed ID is of the FObject type
  81. virtual bool isTypeOf (FClassID s, bool /*askBaseClass*/ = true) const {return classIDsEqual (s, FObject::getFClassID ());}
  82. ///< evaluates if the passed ID is of the FObject type
  83. int32 getRefCount () {return refCount;} ///< returns the current interface reference count
  84. FUnknown* unknownCast () {return this;} ///< get FUnknown interface from object
  85. // FUnknown
  86. virtual tresult PLUGIN_API queryInterface (const TUID _iid, void** obj) SMTG_OVERRIDE; ///< please refer to FUnknown::queryInterface ()
  87. virtual uint32 PLUGIN_API addRef () SMTG_OVERRIDE; ///< please refer to FUnknown::addref ()
  88. virtual uint32 PLUGIN_API release () SMTG_OVERRIDE; ///< please refer to FUnknown::release ()
  89. // IDependent
  90. virtual void PLUGIN_API update (FUnknown* /*changedUnknown*/, int32 /*message*/) SMTG_OVERRIDE {}
  91. ///< empty virtual method that should be overridden by derived classes for data updates upon changes
  92. // IDependency
  93. virtual void addDependent (IDependent* dep); ///< adds dependency to the object
  94. virtual void removeDependent (IDependent* dep); ///< removes dependency from the object
  95. virtual void changed (int32 msg = kChanged); ///< Inform all dependents, that the object has changed.
  96. virtual void deferUpdate (int32 msg = kChanged); ///< Similar to triggerUpdates, except only delivered in idle (usefull in collecting updates).
  97. virtual void updateDone (int32 /* msg */) {} ///< empty virtual method that should be overridden by derived classes
  98. virtual bool isEqualInstance (FUnknown* d) {return this == d;}
  99. static void setUpdateHandler (IUpdateHandler* handler) {gUpdateHandler = handler;} ///< set method for the local attribute
  100. static IUpdateHandler* getUpdateHandler () {return gUpdateHandler;} ///< get method for the local attribute
  101. // static helper functions
  102. static inline bool classIDsEqual (FClassID ci1, FClassID ci2); ///< compares (evaluates) 2 class IDs
  103. static inline FObject* unknownToObject (FUnknown* unknown); ///< pointer conversion from FUnknown to FObject
  104. /** Special UID that is used to cast an FUnknown pointer to a FObject */
  105. static const FUID iid;
  106. //------------------------------------------------------------------------
  107. protected:
  108. int32 refCount; ///< COM-model local reference count
  109. static IUpdateHandler* gUpdateHandler;
  110. };
  111. //------------------------------------------------------------------------
  112. // conversion from FUnknown to FObject
  113. //------------------------------------------------------------------------
  114. inline FObject* FObject::unknownToObject (FUnknown* unknown)
  115. {
  116. FObject* object = 0;
  117. if (unknown)
  118. {
  119. unknown->queryInterface (FObject::iid, (void**)&object);
  120. if (object)
  121. object->release (); // queryInterface has added ref
  122. }
  123. return object;
  124. }
  125. //------------------------------------------------------------------------
  126. inline bool FObject::classIDsEqual (FClassID ci1, FClassID ci2)
  127. {
  128. return (ci1 && ci2) ? (strcmp (ci1, ci2) == 0) : false;
  129. }
  130. //-----------------------------------------------------------------------
  131. /** FCast overload 1 - FObject to FObject */
  132. //-----------------------------------------------------------------------
  133. template <class C>
  134. inline C* FCast (const FObject* object)
  135. {
  136. if (object && object->isTypeOf (C::getFClassID (), true))
  137. return (C*) object;
  138. return 0;
  139. }
  140. //-----------------------------------------------------------------------
  141. /** FCast overload 2 - FUnknown to FObject */
  142. //-----------------------------------------------------------------------
  143. template <class C>
  144. inline C* FCast (FUnknown* unknown)
  145. {
  146. FObject* object = FObject::unknownToObject (unknown);
  147. return FCast<C> (object);
  148. }
  149. //-----------------------------------------------------------------------
  150. /** FUCast - casting from FUnknown to Interface */
  151. //-----------------------------------------------------------------------
  152. template <class C>
  153. inline C* FUCast (FObject* object)
  154. {
  155. return FUnknownPtr<C> (object ? object->unknownCast () : 0);
  156. }
  157. template <class C>
  158. inline C* FUCast (FUnknown* object)
  159. {
  160. return FUnknownPtr<C> (object);
  161. }
  162. //------------------------------------------------------------------------
  163. /** @name Convenience methods that call release or delete respectively
  164. on a pointer if it is non-zero, and then set the pointer to zero.
  165. Note: you should prefer using IPtr or OPtr instead of these methods
  166. whenever possible.
  167. <b>Examples:</b>
  168. @code
  169. ~Foo ()
  170. {
  171. // instead of ...
  172. if (somePointer)
  173. {
  174. somePointer->release ();
  175. somePointer = 0;
  176. }
  177. // ... just being lazy I write
  178. SafeRelease (somePointer)
  179. }
  180. @endcode
  181. */
  182. ///@{
  183. //-----------------------------------------------------------------------
  184. template <class I>
  185. inline void SafeRelease (I *& ptr)
  186. {
  187. if (ptr)
  188. {
  189. ptr->release ();
  190. ptr = 0;
  191. }
  192. }
  193. //-----------------------------------------------------------------------
  194. template <class I>
  195. inline void SafeRelease (IPtr<I> & ptr)
  196. {
  197. ptr = 0;
  198. }
  199. //-----------------------------------------------------------------------
  200. template <class T>
  201. inline void SafeDelete (T *& ptr)
  202. {
  203. if (ptr)
  204. {
  205. delete ptr;
  206. ptr = 0;
  207. }
  208. }
  209. ///@}
  210. //-----------------------------------------------------------------------
  211. template <class T>
  212. inline void AssignShared (T*& dest, T* newPtr)
  213. {
  214. if (dest == newPtr)
  215. return;
  216. if (dest)
  217. dest->release ();
  218. dest = newPtr;
  219. if (dest)
  220. dest->addRef ();
  221. }
  222. //-----------------------------------------------------------------------
  223. template <class T>
  224. inline void AssignSharedDependent (IDependent* _this, T*& dest, T* newPtr)
  225. {
  226. if (dest == newPtr)
  227. return;
  228. if (dest)
  229. dest->removeDependent (_this);
  230. AssignShared (dest, newPtr);
  231. if (dest)
  232. dest->addDependent (_this);
  233. }
  234. //-----------------------------------------------------------------------
  235. template <class T>
  236. inline void AssignSharedDependent (IDependent* _this, IPtr<T>& dest, T* newPtr)
  237. {
  238. if (dest == newPtr)
  239. return;
  240. if (dest)
  241. dest->removeDependent (_this);
  242. dest = newPtr;
  243. if (dest)
  244. dest->addDependent (_this);
  245. }
  246. //-----------------------------------------------------------------------
  247. template <class T>
  248. inline void SafeReleaseDependent (IDependent* _this, T*& dest)
  249. {
  250. if (dest)
  251. dest->removeDependent (_this);
  252. SafeRelease (dest);
  253. }
  254. //-----------------------------------------------------------------------
  255. template <class T>
  256. inline void SafeReleaseDependent (IDependent* _this, IPtr<T>& dest)
  257. {
  258. if (dest)
  259. dest->removeDependent (_this);
  260. SafeRelease (dest);
  261. }
  262. //------------------------------------------------------------------------
  263. /** Automatic creation and destruction of singleton instances. */
  264. namespace Singleton {
  265. /** registers an instance (type FObject) */
  266. void registerInstance (FObject** o);
  267. /** Returns true when singleton instances were already released. */
  268. bool isTerminated ();
  269. /** lock and unlock the singleton registration for multi-threading safety */
  270. void lockRegister ();
  271. void unlockRegister ();
  272. }
  273. //------------------------------------------------------------------------
  274. } // namespace Steinberg
  275. //-----------------------------------------------------------------------
  276. #define SINGLETON(ClassName) \
  277. static ClassName* instance (bool create = true) \
  278. { \
  279. static Steinberg::FObject* inst = nullptr; \
  280. if (inst == nullptr && create && Steinberg::Singleton::isTerminated () == false) \
  281. { \
  282. Steinberg::Singleton::lockRegister (); \
  283. if (inst == nullptr) \
  284. { \
  285. inst = NEW ClassName; \
  286. Steinberg::Singleton::registerInstance (&inst); \
  287. } \
  288. Steinberg::Singleton::unlockRegister (); \
  289. } \
  290. return (ClassName*)inst; \
  291. }
  292. //-----------------------------------------------------------------------
  293. #define OBJ_METHODS(className, baseClass) \
  294. static inline Steinberg::FClassID getFClassID () {return (#className);} \
  295. virtual Steinberg::FClassID isA () const SMTG_OVERRIDE {return className::getFClassID ();} \
  296. virtual bool isA (Steinberg::FClassID s) const SMTG_OVERRIDE {return isTypeOf (s, false);} \
  297. virtual bool isTypeOf (Steinberg::FClassID s, bool askBaseClass = true) const SMTG_OVERRIDE \
  298. { return (classIDsEqual (s, #className) ? true : (askBaseClass ? baseClass::isTypeOf (s, true) : false)); }
  299. //------------------------------------------------------------------------
  300. /** Delegate refcount functions to BaseClass.
  301. BaseClase must implement ref counting.
  302. */
  303. //------------------------------------------------------------------------
  304. #define REFCOUNT_METHODS(BaseClass) \
  305. virtual Steinberg::uint32 PLUGIN_API addRef ()SMTG_OVERRIDE{ return BaseClass::addRef (); } \
  306. virtual Steinberg::uint32 PLUGIN_API release ()SMTG_OVERRIDE{ return BaseClass::release (); }
  307. //------------------------------------------------------------------------
  308. /** @name Macros to implement FUnknown::queryInterface ().
  309. <b>Examples:</b>
  310. @code
  311. class Foo : public FObject, public IFoo2, public IFoo3
  312. {
  313. ...
  314. DEFINE_INTERFACES
  315. DEF_INTERFACE (IFoo2)
  316. DEF_INTERFACE (IFoo3)
  317. END_DEFINE_INTERFACES (FObject)
  318. REFCOUNT_METHODS(FObject)
  319. // Implement IFoo2 interface ...
  320. // Implement IFoo3 interface ...
  321. ...
  322. };
  323. @endcode
  324. */
  325. ///@{
  326. //------------------------------------------------------------------------
  327. /** Start defining interfaces. */
  328. //------------------------------------------------------------------------
  329. #define DEFINE_INTERFACES \
  330. Steinberg::tresult PLUGIN_API queryInterface (const Steinberg::TUID iid, void** obj) SMTG_OVERRIDE \
  331. {
  332. //------------------------------------------------------------------------
  333. /** Add a interfaces. */
  334. //------------------------------------------------------------------------
  335. #define DEF_INTERFACE(InterfaceName) \
  336. QUERY_INTERFACE (iid, obj, InterfaceName::iid, InterfaceName)
  337. //------------------------------------------------------------------------
  338. /** End defining interfaces. */
  339. //------------------------------------------------------------------------
  340. #define END_DEFINE_INTERFACES(BaseClass) \
  341. return BaseClass::queryInterface (iid, obj); \
  342. }
  343. ///@}
  344. //------------------------------------------------------------------------
  345. /** @name Convenient macros to implement Steinberg::FUnknown::queryInterface ().
  346. <b>Examples:</b>
  347. @code
  348. class Foo : public FObject, public IFoo2, public IFoo3
  349. {
  350. ...
  351. DEF_INTERFACES_2(IFoo2,IFoo3,FObject)
  352. REFCOUNT_METHODS(FObject)
  353. ...
  354. };
  355. @endcode
  356. */
  357. ///@{
  358. //------------------------------------------------------------------------
  359. #define DEF_INTERFACES_1(InterfaceName,BaseClass) \
  360. DEFINE_INTERFACES \
  361. DEF_INTERFACE (InterfaceName) \
  362. END_DEFINE_INTERFACES (BaseClass)
  363. //------------------------------------------------------------------------
  364. #define DEF_INTERFACES_2(InterfaceName1,InterfaceName2,BaseClass) \
  365. DEFINE_INTERFACES \
  366. DEF_INTERFACE (InterfaceName1) \
  367. DEF_INTERFACE (InterfaceName2) \
  368. END_DEFINE_INTERFACES (BaseClass)
  369. //------------------------------------------------------------------------
  370. #define DEF_INTERFACES_3(InterfaceName1,InterfaceName2,InterfaceName3,BaseClass) \
  371. DEFINE_INTERFACES \
  372. DEF_INTERFACE (InterfaceName1) \
  373. DEF_INTERFACE (InterfaceName2) \
  374. DEF_INTERFACE (InterfaceName3) \
  375. END_DEFINE_INTERFACES (BaseClass)
  376. //------------------------------------------------------------------------
  377. #define DEF_INTERFACES_4(InterfaceName1,InterfaceName2,InterfaceName3,InterfaceName4,BaseClass) \
  378. DEFINE_INTERFACES \
  379. DEF_INTERFACE (InterfaceName1) \
  380. DEF_INTERFACE (InterfaceName2) \
  381. DEF_INTERFACE (InterfaceName3) \
  382. DEF_INTERFACE (InterfaceName4) \
  383. END_DEFINE_INTERFACES (BaseClass)
  384. ///@}
  385. //------------------------------------------------------------------------
  386. /** @name Convenient macros to implement Steinberg::FUnknown methods.
  387. <b>Examples:</b>
  388. @code
  389. class Foo : public FObject, public IFoo2, public IFoo3
  390. {
  391. ...
  392. FUNKNOWN_METHODS2(IFoo2,IFoo3,FObject)
  393. ...
  394. };
  395. @endcode
  396. */
  397. ///@{
  398. #define FUNKNOWN_METHODS(InterfaceName,BaseClass) \
  399. DEF_INTERFACES_1(InterfaceName,BaseClass) \
  400. REFCOUNT_METHODS(BaseClass)
  401. #define FUNKNOWN_METHODS2(InterfaceName1,InterfaceName2,BaseClass) \
  402. DEF_INTERFACES_2(InterfaceName1,InterfaceName2,BaseClass) \
  403. REFCOUNT_METHODS(BaseClass)
  404. #define FUNKNOWN_METHODS3(InterfaceName1,InterfaceName2,InterfaceName3,BaseClass) \
  405. DEF_INTERFACES_3(InterfaceName1,InterfaceName2,InterfaceName3,BaseClass) \
  406. REFCOUNT_METHODS(BaseClass)
  407. #define FUNKNOWN_METHODS4(InterfaceName1,InterfaceName2,InterfaceName3,InterfaceName4,BaseClass) \
  408. DEF_INTERFACES_4(InterfaceName1,InterfaceName2,InterfaceName3,InterfaceName4,BaseClass) \
  409. REFCOUNT_METHODS(BaseClass)
  410. ///@}
  411. //------------------------------------------------------------------------
  412. //------------------------------------------------------------------------
  413. #if COM_COMPATIBLE
  414. //------------------------------------------------------------------------
  415. /** @name Macros to implement IUnknown interfaces with FObject.
  416. <b>Examples:</b>
  417. @code
  418. class MyEnumFormat : public FObject, IEnumFORMATETC
  419. {
  420. ...
  421. COM_UNKNOWN_METHODS (IEnumFORMATETC, IUnknown)
  422. ...
  423. };
  424. @endcode
  425. */
  426. ///@{
  427. //------------------------------------------------------------------------
  428. #define IUNKNOWN_REFCOUNT_METHODS(BaseClass) \
  429. STDMETHOD_ (ULONG, AddRef) (void) {return BaseClass::addRef ();} \
  430. STDMETHOD_ (ULONG, Release) (void) {return BaseClass::release ();}
  431. //------------------------------------------------------------------------
  432. #define COM_QUERY_INTERFACE(iid, obj, InterfaceName) \
  433. if (riid == __uuidof(InterfaceName)) \
  434. { \
  435. addRef (); \
  436. *obj = (InterfaceName*)this; \
  437. return kResultOk; \
  438. }
  439. //------------------------------------------------------------------------
  440. #define COM_OBJECT_QUERY_INTERFACE(InterfaceName,BaseClass) \
  441. STDMETHOD (QueryInterface) (REFIID riid, void** object) \
  442. { \
  443. COM_QUERY_INTERFACE (riid, object, InterfaceName) \
  444. return BaseClass::queryInterface ((FIDString)&riid, object); \
  445. }
  446. //------------------------------------------------------------------------
  447. #define COM_UNKNOWN_METHODS(InterfaceName,BaseClass) \
  448. COM_OBJECT_QUERY_INTERFACE(InterfaceName,BaseClass) \
  449. IUNKNOWN_REFCOUNT_METHODS(BaseClass)
  450. ///@}
  451. #endif // COM_COMPATIBLE