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.

387 lines
9.4KB

  1. //-----------------------------------------------------------------------------
  2. // Project : SDK Core
  3. //
  4. // Category : SDK Core Interfaces
  5. // Filename : pluginterfaces/base/smartpointer.h
  6. // Created by : Steinberg, 01/2004
  7. // Description : Basic Interface
  8. //
  9. //-----------------------------------------------------------------------------
  10. // This file is part of a Steinberg SDK. It is subject to the license terms
  11. // in the LICENSE file found in the top-level directory of this distribution
  12. // and at www.steinberg.net/sdklicenses.
  13. // No part of the SDK, including this file, may be copied, modified, propagated,
  14. // or distributed except according to the terms contained in the LICENSE file.
  15. //-----------------------------------------------------------------------------
  16. #pragma once
  17. #include "pluginterfaces/base/fplatform.h"
  18. #if SMTG_CPP11_STDLIBSUPPORT
  19. #include <utility>
  20. #endif
  21. //------------------------------------------------------------------------
  22. namespace Steinberg {
  23. //------------------------------------------------------------------------
  24. // IPtr
  25. //------------------------------------------------------------------------
  26. /** IPtr - Smart pointer template class.
  27. \ingroup pluginBase
  28. - can be used as an I* pointer
  29. - handles refCount of the interface
  30. - Usage example:
  31. \code
  32. IPtr<IPath> path (sharedPath);
  33. if (path)
  34. path->ascend ();
  35. \endcode
  36. */
  37. //------------------------------------------------------------------------
  38. template <class I>
  39. class IPtr
  40. {
  41. public:
  42. //------------------------------------------------------------------------
  43. inline IPtr (I* ptr, bool addRef = true);
  44. inline IPtr (const IPtr&);
  45. template <class T>
  46. inline IPtr (const IPtr<T>& other) : ptr (other.get ())
  47. {
  48. if (ptr)
  49. ptr->addRef ();
  50. }
  51. inline IPtr ();
  52. inline ~IPtr ();
  53. inline I* operator= (I* ptr);
  54. inline IPtr& operator= (const IPtr& other);
  55. template <class T>
  56. inline IPtr& operator= (const IPtr<T>& other)
  57. {
  58. operator= (other.get ());
  59. return *this;
  60. }
  61. inline operator I* () const { return ptr; } // act as I*
  62. inline I* operator-> () const { return ptr; } // act as I*
  63. inline I* get () const { return ptr; }
  64. #if SMTG_CPP11_STDLIBSUPPORT
  65. inline IPtr (IPtr<I>&& movePtr) SMTG_NOEXCEPT : ptr (movePtr.take ()) { }
  66. template <typename T>
  67. inline IPtr (IPtr<T>&& movePtr) SMTG_NOEXCEPT : ptr (movePtr.take ()) { }
  68. inline IPtr& operator= (IPtr<I>&& movePtr)
  69. {
  70. if (ptr)
  71. ptr->release ();
  72. ptr = movePtr.take ();
  73. return *this;
  74. }
  75. template <typename T>
  76. inline IPtr& operator= (IPtr<T>&& movePtr)
  77. {
  78. if (ptr)
  79. ptr->release ();
  80. ptr = movePtr.take ();
  81. return *this;
  82. }
  83. inline void reset (I* obj = nullptr)
  84. {
  85. if (ptr)
  86. ptr->release();
  87. ptr = obj;
  88. }
  89. I* take () SMTG_NOEXCEPT
  90. {
  91. I* out = ptr;
  92. ptr = nullptr;
  93. return out;
  94. }
  95. template <typename T>
  96. static IPtr<T> adopt (T* obj) SMTG_NOEXCEPT { return IPtr<T> (obj, false); }
  97. #endif
  98. //------------------------------------------------------------------------
  99. protected:
  100. I* ptr;
  101. };
  102. //------------------------------------------------------------------------
  103. template <class I>
  104. inline IPtr<I>::IPtr (I* _ptr, bool addRef) : ptr (_ptr)
  105. {
  106. if (ptr && addRef)
  107. ptr->addRef ();
  108. }
  109. //------------------------------------------------------------------------
  110. template <class I>
  111. inline IPtr<I>::IPtr (const IPtr<I>& other) : ptr (other.ptr)
  112. {
  113. if (ptr)
  114. ptr->addRef ();
  115. }
  116. //------------------------------------------------------------------------
  117. template <class I>
  118. inline IPtr<I>::IPtr () : ptr (0)
  119. {
  120. }
  121. //------------------------------------------------------------------------
  122. template <class I>
  123. inline IPtr<I>::~IPtr ()
  124. {
  125. if (ptr)
  126. {
  127. ptr->release ();
  128. ptr = nullptr; //TODO_CORE: how much does this cost? is this something hiding for us?
  129. }
  130. }
  131. //------------------------------------------------------------------------
  132. template <class I>
  133. inline I* IPtr<I>::operator= (I* _ptr)
  134. {
  135. if (_ptr != ptr)
  136. {
  137. if (ptr)
  138. ptr->release ();
  139. ptr = _ptr;
  140. if (ptr)
  141. ptr->addRef ();
  142. }
  143. return ptr;
  144. }
  145. //------------------------------------------------------------------------
  146. template <class I>
  147. inline IPtr<I>& IPtr<I>::operator= (const IPtr<I>& _ptr)
  148. {
  149. operator= (_ptr.ptr);
  150. return *this;
  151. }
  152. //------------------------------------------------------------------------
  153. /** OPtr - "owning" smart pointer used for newly created FObjects.
  154. \ingroup pluginBase
  155. FUnknown implementations are supposed to have a refCount of 1 right after creation.
  156. So using an IPtr on newly created objects would lead to a leak.
  157. Instead the OPtr can be used in this case. \n
  158. Example:
  159. \code
  160. OPtr<IPath> path = FHostCreate (IPath, hostClasses);
  161. // no release is needed...
  162. \endcode
  163. The assignment operator takes ownership of a new object and releases the old.
  164. So its safe to write:
  165. \code
  166. OPtr<IPath> path = FHostCreate (IPath, hostClasses);
  167. path = FHostCreate (IPath, hostClasses);
  168. path = 0;
  169. \endcode
  170. This is the difference to using an IPtr with addRef=false.
  171. \code
  172. // DONT DO THIS:
  173. IPtr<IPath> path (FHostCreate (IPath, hostClasses), false);
  174. path = FHostCreate (IPath, hostClasses);
  175. path = 0;
  176. \endcode
  177. This will lead to a leak!
  178. */
  179. //------------------------------------------------------------------------
  180. template <class I>
  181. class OPtr : public IPtr<I>
  182. {
  183. public:
  184. //------------------------------------------------------------------------
  185. inline OPtr (I* p) : IPtr<I> (p, false) {}
  186. inline OPtr (const IPtr<I>& p) : IPtr<I> (p) {}
  187. inline OPtr (const OPtr<I>& p) : IPtr<I> (p) {}
  188. inline OPtr () {}
  189. inline I* operator= (I* _ptr)
  190. {
  191. if (_ptr != this->ptr)
  192. {
  193. if (this->ptr)
  194. this->ptr->release ();
  195. this->ptr = _ptr;
  196. }
  197. return this->ptr;
  198. }
  199. };
  200. //------------------------------------------------------------------------
  201. /** Assigning newly created object to an IPtr.
  202. Example:
  203. \code
  204. IPtr<IPath> path = owned (FHostCreate (IPath, hostClasses));
  205. \endcode
  206. which is a slightly shorter form of writing:
  207. \code
  208. IPtr<IPath> path = OPtr<IPath> (FHostCreate (IPath, hostClasses));
  209. \endcode
  210. */
  211. template <class I>
  212. IPtr<I> owned (I* p)
  213. {
  214. return IPtr<I> (p, false);
  215. }
  216. /** Assigning shared object to an IPtr.
  217. Example:
  218. \code
  219. IPtr<IPath> path = shared (iface.getXY ());
  220. \endcode
  221. */
  222. template <class I>
  223. IPtr<I> shared (I* p)
  224. {
  225. return IPtr<I> (p, true);
  226. }
  227. #if SMTG_CPP11_STDLIBSUPPORT
  228. //------------------------------------------------------------------------
  229. // Ownership functionality
  230. //------------------------------------------------------------------------
  231. namespace SKI {
  232. namespace Detail {
  233. struct Adopt;
  234. } // Detail
  235. /** Strong typedef for shared reference counted objects.
  236. * Use SKI::adopt to unwrap the provided object.
  237. * @tparam T Referenced counted type.
  238. */
  239. template <typename T>
  240. class Shared
  241. {
  242. friend struct Detail::Adopt;
  243. T* obj = nullptr;
  244. };
  245. /** Strong typedef for transferring the ownership of reference counted objects.
  246. * Use SKI::adopt to unwrap the provided object.
  247. * After calling adopt the reference in this object is null.
  248. * @tparam T Referenced counted type.
  249. */
  250. template <typename T>
  251. class Owned
  252. {
  253. friend struct Detail::Adopt;
  254. T* obj = nullptr;
  255. };
  256. /** Strong typedef for using reference counted objects.
  257. * Use SKI::adopt to unwrap the provided object.
  258. * After calling adopt the reference in this object is null.
  259. * @tparam T Referenced counted type.
  260. */
  261. template <typename T>
  262. class Used
  263. {
  264. friend struct Detail::Adopt;
  265. T* obj = nullptr;
  266. };
  267. namespace Detail {
  268. struct Adopt
  269. {
  270. template <typename T>
  271. static IPtr<T> adopt (Shared<T>& ref)
  272. {
  273. using Steinberg::shared;
  274. return shared (ref.obj);
  275. }
  276. template <typename T>
  277. static IPtr<T> adopt (Owned<T>& ref)
  278. {
  279. using Steinberg::owned;
  280. IPtr<T> out = owned (ref.obj);
  281. ref.obj = nullptr;
  282. return out;
  283. }
  284. template <typename T>
  285. static T* adopt (Used<T>& ref)
  286. {
  287. return ref.obj;
  288. }
  289. template <template <typename> class OwnerType, typename T>
  290. static OwnerType<T> toOwnerType (T* obj)
  291. {
  292. OwnerType<T> out;
  293. out.obj = obj;
  294. return out;
  295. }
  296. };
  297. } // Detail
  298. /** Common function to adopt referenced counted object.
  299. * @tparam T Referenced counted type.
  300. * @param ref The reference to be adopted in a smart pointer.
  301. */
  302. template <typename T>
  303. IPtr<T> adopt (Shared<T>& ref) { return Detail::Adopt::adopt (ref); }
  304. template <typename T>
  305. IPtr<T> adopt (Shared<T>&& ref) { return Detail::Adopt::adopt (ref); }
  306. /** Common function to adopt referenced counted object.
  307. * @tparam T Referenced counted type.
  308. * @param ref The reference to be adopted in a smart pointer.
  309. */
  310. template <typename T>
  311. IPtr<T> adopt (Owned<T>& ref) { return Detail::Adopt::adopt (ref); }
  312. template <typename T>
  313. IPtr<T> adopt (Owned<T>&& ref) { return Detail::Adopt::adopt (ref); }
  314. /** Common function to adopt referenced counted object.
  315. * @tparam T Referenced counted type.
  316. * @param ref The reference to be adopted in a smart pointer.
  317. */
  318. template <typename T>
  319. T* adopt (Used<T>& ref) { return Detail::Adopt::adopt (ref); }
  320. template <typename T>
  321. T* adopt (Used<T>&& ref) { return Detail::Adopt::adopt (ref); }
  322. /** Common function to wrap owned instances. */
  323. template <typename T>
  324. Owned<T> toOwned (T* obj) { return Detail::Adopt::toOwnerType<Owned> (obj); }
  325. /** Common function to wrap shared instances. */
  326. template <typename T>
  327. Shared<T> toShared (T* obj) { return Detail::Adopt::toOwnerType<Shared> (obj); }
  328. /** Common function to wrap used instances. */
  329. template <typename T>
  330. Used<T> toUsed (T* obj) { return Detail::Adopt::toOwnerType<Used> (obj); }
  331. //------------------------------------------------------------------------
  332. } // SKI
  333. #endif
  334. } // Steinberg