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.

614 lines
18 KiB

  1. /* /////////////////////////////////////////////////////////////////////////
  2. * File: stlsoft/smartptr/ref_ptr.hpp (originally MLRelItf.h, ::SynesisStd)
  3. *
  4. * Purpose: Contains the ref_ptr template class.
  5. *
  6. * Created: 2nd November 1994
  7. * Updated: 14th May 2010
  8. *
  9. * Home: http://stlsoft.org/
  10. *
  11. * Copyright (c) 1994-2010, Matthew Wilson and Synesis Software
  12. * All rights reserved.
  13. *
  14. * Redistribution and use in source and binary forms, with or without
  15. * modification, are permitted provided that the following conditions are met:
  16. *
  17. * - Redistributions of source code must retain the above copyright notice, this
  18. * 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(s) of Matthew Wilson and Synesis Software nor the names of
  23. * any contributors may be used to endorse or promote products derived from
  24. * this software without specific prior written permission.
  25. *
  26. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  27. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  28. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  29. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  30. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  31. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  32. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  33. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  34. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  35. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  36. * POSSIBILITY OF SUCH DAMAGE.
  37. *
  38. * ////////////////////////////////////////////////////////////////////// */
  39. /** \file stlsoft/smartptr/ref_ptr.hpp
  40. *
  41. * \brief [C++ only] Definition of the stlsoft::ref_ptr smart
  42. * pointer class template
  43. * (\ref group__library__smart_pointers "Smart Pointers" Library).
  44. */
  45. #ifndef STLSOFT_INCL_STLSOFT_SMARTPTR_HPP_REF_PTR
  46. #define STLSOFT_INCL_STLSOFT_SMARTPTR_HPP_REF_PTR
  47. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  48. # define STLSOFT_VER_STLSOFT_SMARTPTR_HPP_REF_PTR_MAJOR 5
  49. # define STLSOFT_VER_STLSOFT_SMARTPTR_HPP_REF_PTR_MINOR 3
  50. # define STLSOFT_VER_STLSOFT_SMARTPTR_HPP_REF_PTR_REVISION 2
  51. # define STLSOFT_VER_STLSOFT_SMARTPTR_HPP_REF_PTR_EDIT 489
  52. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  53. /* /////////////////////////////////////////////////////////////////////////
  54. * Includes
  55. */
  56. #ifndef STLSOFT_INCL_STLSOFT_H_STLSOFT
  57. # include <stlsoft/stlsoft.h>
  58. #endif /* !STLSOFT_INCL_STLSOFT_H_STLSOFT */
  59. /* /////////////////////////////////////////////////////////////////////////
  60. * Namespace
  61. */
  62. #ifndef _STLSOFT_NO_NAMESPACE
  63. namespace stlsoft
  64. {
  65. #endif /* _STLSOFT_NO_NAMESPACE */
  66. /* /////////////////////////////////////////////////////////////////////////
  67. * Helper shims
  68. */
  69. /** \brief Control shim for adding a reference on a reference-counted
  70. * interface (RCI)
  71. *
  72. * \ingroup group__library__smart_pointers
  73. *
  74. * \note The generic shim expects the RCI to have a method named AddRef(), which
  75. * has either no parameters, or has all default parameters
  76. *
  77. * \note The behaviour of the ref_ptr is undefined if this method throws an
  78. * exception
  79. */
  80. template<ss_typename_param_k I>
  81. inline void add_reference(I* pi)
  82. {
  83. STLSOFT_ASSERT(NULL != pi);
  84. pi->AddRef();
  85. }
  86. /** \brief Control shim for releasing a reference on a reference-counted
  87. * interface (RCI)
  88. *
  89. * \ingroup group__library__smart_pointers
  90. *
  91. * \note The generic shim expects the RCI to have a method named Release(), which
  92. * has either no parameters, or has all default parameters
  93. *
  94. * \note The behaviour of the ref_ptr is undefined if this method throws an
  95. * exception
  96. */
  97. template<ss_typename_param_k I>
  98. inline void release_reference(I* pi)
  99. {
  100. STLSOFT_ASSERT(NULL != pi);
  101. pi->Release();
  102. }
  103. /* /////////////////////////////////////////////////////////////////////////
  104. * Classes
  105. */
  106. /** \brief This class provides RAII-safe handling of reference-counted
  107. * interfaces (RCIs). Its notable feature is that it supports forward
  108. * declaration of the leaf interface so long as the base counting
  109. * interface is visible in the scope of the template parameterisation.
  110. *
  111. * \ingroup group__library__smart_pointers
  112. *
  113. * \param T The counted type (i.e. a concrete class)
  114. * \param I The interface type
  115. * \param U The upcast intermediate type
  116. */
  117. template< ss_typename_param_k T
  118. , ss_typename_param_k I = T
  119. , ss_typename_param_k U = I
  120. >
  121. class ref_ptr
  122. {
  123. /// \name Types
  124. /// @{
  125. public:
  126. /// \brief The Boolean type
  127. typedef bool_t bool_type;
  128. /// \brief The interface type: the type of the RCI (Reference-Counted Interface)
  129. typedef I interface_type;
  130. /// \brief The counted type: the concrete type of the objects whose instances will be managed
  131. typedef T counted_type;
  132. /// \brief The up-cast type: the type used to disambiguate upcasts between T and I
  133. typedef U upcast_type;
  134. /// \brief The current instantiation of the type
  135. typedef ref_ptr<T, I, U> class_type;
  136. /// \brief This to be member-type-compatible with std::auto_ptr
  137. typedef I element_type;
  138. /// \brief This is to be compatible with the get_invoker component
  139. typedef counted_type* resource_type;
  140. typedef counted_type const* const_resource_type;
  141. /// @}
  142. /// \name Implementation
  143. /// @{
  144. private:
  145. /// \brief Helper function to effect downcast from interface type to counted type
  146. static counted_type* c_from_i(interface_type* i)
  147. {
  148. return static_cast<counted_type*>(static_cast<upcast_type*>(i));
  149. }
  150. /// \brief Helper function to effect downcast from interface type to counted type
  151. static counted_type const* c_from_i(interface_type const* i)
  152. {
  153. return static_cast<counted_type const*>(static_cast<upcast_type const*>(i));
  154. }
  155. /// \brief Helper function to effect upcast from counted type to interface type
  156. static interface_type* i_from_c(counted_type* c)
  157. {
  158. return static_cast<upcast_type*>(c);
  159. }
  160. #if defined(STLSOFT_COMPILER_IS_MSVC) && \
  161. _MSC_VER == 1300
  162. /// \brief Helper function to effect upcast from const counted type to interface type
  163. static interface_type* i_from_const_c(counted_type const* cc)
  164. {
  165. counted_type* c = const_cast<counted_type*>(cc);
  166. return i_from_c(c);
  167. }
  168. #endif /* compiler */
  169. /// @}
  170. /// \name Construction
  171. /// @{
  172. public:
  173. /// \brief Default constructor
  174. ///
  175. /// Constructs and empty instance
  176. ref_ptr()
  177. : m_pi(NULL)
  178. {}
  179. /// \brief Construct from a raw pointer to the counted type, and a boolean that
  180. /// indicates whether a reference should be taken on the instance.
  181. ///
  182. /// \param c Pointer to a counted_type. May be NULL
  183. /// \param bAddRef parameter that determines whether reference will be
  184. /// <i>consumed</i> (<code>false</code>) or <i>borrowed</i>
  185. /// (<code>true</code>).
  186. ///
  187. /// \note It is usual that ref_ptr is used to "sink" an instance, i.e. to take
  188. /// ownership of it. In such a case, \c false should be specified as the second
  189. /// parameter. If, however, a reference is being "borrowed", then \c true should
  190. /// be specified.
  191. ref_ptr(counted_type* c, bool_type bAddRef)
  192. : m_pi(i_from_c(c))
  193. {
  194. if( bAddRef &&
  195. NULL != m_pi)
  196. {
  197. add_reference(m_pi);
  198. }
  199. }
  200. /// \brief Creates a copy of the given ref_ptr instance, and increments the
  201. /// reference count on its referent object, if any
  202. ///
  203. /// \param rhs The instance to copy
  204. ref_ptr(class_type const& rhs)
  205. : m_pi(rhs.m_pi)
  206. {
  207. if(NULL != m_pi)
  208. {
  209. add_reference(m_pi);
  210. }
  211. }
  212. #if !defined(STLSOFT_COMPILER_IS_MSVC) || \
  213. _MSC_VER > 1100
  214. /// \brief Copy constructs from an instance with different interface and/or
  215. /// counted type
  216. ///
  217. /// \note The interface types of the copying and copied instance must be
  218. /// compatible
  219. template< ss_typename_param_k T2
  220. , ss_typename_param_k I2
  221. , ss_typename_param_k U2
  222. >
  223. # if defined(STLSOFT_COMPILER_IS_MSVC) && \
  224. _MSC_VER == 1300
  225. ref_ptr(ref_ptr<T2, I2, U2> const& rhs)
  226. # if 0
  227. // We cannot use this form, as it would lead to instances with different
  228. // counted_type being cross cast invisibly. This would be a *very bad thing*
  229. : m_pi(rhs.m_pi)
  230. # else /* ? 0 */
  231. : m_pi(i_from_const_c(rhs.get()))
  232. # endif /* 0 */
  233. {
  234. if(NULL != m_pi)
  235. {
  236. add_reference(m_pi);
  237. }
  238. }
  239. # else /* ? compiler */
  240. ref_ptr(ref_ptr<T2, I2, U2>& rhs)
  241. # if 0
  242. // We cannot use this form, as it would lead to instances with different
  243. // counted_type being cross cast invisibly. This would be a *very bad thing*
  244. : m_pi(rhs.m_pi)
  245. # else /* ? 0 */
  246. : m_pi(i_from_c(rhs.get()))
  247. # endif /* 0 */
  248. {
  249. if(NULL != m_pi)
  250. {
  251. add_reference(m_pi);
  252. }
  253. }
  254. # endif /* compiler */
  255. #endif /* compiler */
  256. #if !defined(STLSOFT_COMPILER_IS_INTEL) && \
  257. !defined(STLSOFT_COMPILER_IS_MWERKS) && \
  258. 0
  259. template< ss_typename_param_k I2
  260. , ss_typename_param_k U2
  261. >
  262. explicit ref_ptr(ref_ptr<T, I2, U2>& rhs)
  263. : m_pi(rhs.m_pi)
  264. {
  265. if(NULL != m_pi)
  266. {
  267. add_reference(m_pi);
  268. }
  269. }
  270. #endif /* compiler */
  271. /// \brief Destructor
  272. ///
  273. /// If the ref_ptr instance is still holding a pointer to a managed instance,
  274. /// it will be released.
  275. ~ref_ptr() stlsoft_throw_0()
  276. {
  277. if(NULL != m_pi)
  278. {
  279. release_reference(m_pi);
  280. }
  281. }
  282. /// \brief Copy assignment from a ref_ptr instance of the same type
  283. ///
  284. /// \note It is strongly exception-safe, as long as the implementations of the
  285. /// add-ref and release functions - as utilised in the \c add_reference() and
  286. /// \c release_reference() control shims - do not throw (which they must not).
  287. class_type& operator =(class_type const& rhs)
  288. {
  289. class_type t(rhs);
  290. t.swap(*this);
  291. return *this;
  292. }
  293. #if !defined(STLSOFT_COMPILER_IS_MSVC) || \
  294. ( _MSC_VER > 1100 && \
  295. _MSC_VER != 1300)
  296. /// \brief Copy assignment from an instance of ref_ptr with a different counted_type (but
  297. /// the same interface type).
  298. ///
  299. /// \note This function template uses the copy constructor template, and has the same
  300. /// instantiation restrictions
  301. ///
  302. /// \note It is strongly exception-safe, as long as the implementations of the
  303. /// add-ref and release functions - as utilised in the \c add_reference() and
  304. /// \c release_reference() control shims - do not throw (which they must not).
  305. template< ss_typename_param_k T2
  306. , ss_typename_param_k U2
  307. >
  308. class_type& operator =(ref_ptr<T2, I, U2>& rhs)
  309. {
  310. class_type t(rhs);
  311. t.swap(*this);
  312. return *this;
  313. }
  314. #endif /* compiler */
  315. #if !defined(STLSOFT_COMPILER_IS_INTEL) && \
  316. !defined(STLSOFT_COMPILER_IS_MWERKS) && \
  317. 0
  318. template< ss_typename_param_k I2
  319. , ss_typename_param_k U2
  320. >
  321. class_type& operator =(ref_ptr<T, I2, U2>& rhs)
  322. {
  323. class_type t(rhs);
  324. t.swap(*this);
  325. return *this;
  326. }
  327. #endif /* compiler */
  328. /// @}
  329. /// \name Operations
  330. /// @{
  331. public:
  332. /// \brief Swaps the managed instance of \c this with \c rhs
  333. ///
  334. /// \note It provides the no-throw guarantee
  335. void swap(class_type& rhs)
  336. {
  337. interface_type* t = rhs.m_pi;
  338. rhs.m_pi = m_pi;
  339. m_pi = t;
  340. }
  341. /// \brief Assigns a reference-counted type to the smart pointer.
  342. ///
  343. /// \param c Pointer to a counted_type. May be NULL
  344. /// \param bAddRef parameter that determines whether reference will be
  345. /// <i>consumed</i> (<code>false</code>) or <i>borrowed</i>
  346. /// (<code>true</code>).
  347. void set(counted_type* c, bool_type bAddRef)
  348. {
  349. class_type t(c, bAddRef);
  350. t.swap(*this);
  351. }
  352. /// Closes the instance, releasing the managed pointer.
  353. ///
  354. /// \note Calling this method more than once has no effect.
  355. void close()
  356. {
  357. if(NULL != m_pi)
  358. {
  359. release_reference(m_pi);
  360. m_pi = NULL;
  361. }
  362. }
  363. /// \brief Detaches the managed instance, and returns it to the caller, which
  364. /// takes responsibility for ensuring that the resource is not leaked
  365. counted_type* detach()
  366. {
  367. counted_type* r = class_type::c_from_i(m_pi);
  368. m_pi = NULL;
  369. return r;
  370. }
  371. /// @}
  372. /// \name Equality Comparison
  373. /// @{
  374. public:
  375. /// \brief Evaluates whether two instances are equal
  376. bool_type equal(class_type const& rhs) const
  377. {
  378. return m_pi == rhs.m_pi;
  379. }
  380. /// @}
  381. /// \name Accessors
  382. /// @{
  383. public:
  384. /// \brief Determines whether the instance is empty
  385. bool_type empty() const
  386. {
  387. return NULL == m_pi;
  388. }
  389. /// \brief Determines whether the instance is empty
  390. bool_type operator !() const
  391. {
  392. return empty();
  393. }
  394. /// \brief Provides raw-pointer access to the instance
  395. counted_type* get() const
  396. {
  397. return class_type::c_from_i(m_pi);
  398. }
  399. /// \brief Returns the interface pointer
  400. ///
  401. /// \pre The instance must not be empty; otherwise behaviour is
  402. /// undefined
  403. counted_type* operator ->()
  404. {
  405. STLSOFT_MESSAGE_ASSERT("Dereferencing a NULL pointer!", NULL != m_pi);
  406. return class_type::c_from_i(m_pi);
  407. }
  408. /// \brief Returns the interface pointer
  409. ///
  410. /// \pre The instance must not be empty; otherwise behaviour is
  411. /// undefined
  412. counted_type const* operator ->() const
  413. {
  414. STLSOFT_MESSAGE_ASSERT("Dereferencing a NULL pointer!", NULL != m_pi);
  415. return class_type::c_from_i(m_pi);
  416. }
  417. /// \brief Returns a reference to the managed instance
  418. ///
  419. /// \pre The instance must not be empty; otherwise behaviour is
  420. /// undefined
  421. counted_type& operator *()
  422. {
  423. STLSOFT_MESSAGE_ASSERT("Dereferencing a NULL pointer!", NULL != m_pi);
  424. return *class_type::c_from_i(m_pi);
  425. }
  426. /// \brief Returns a reference to the managed instance
  427. ///
  428. /// \pre The instance must not be empty; otherwise behaviour is
  429. /// undefined
  430. counted_type const& operator *() const
  431. {
  432. STLSOFT_MESSAGE_ASSERT("Dereferencing a NULL pointer!", NULL != m_pi);
  433. return *class_type::c_from_i(m_pi);
  434. }
  435. /// @}
  436. /// \name Members
  437. /// @{
  438. private:
  439. interface_type* m_pi;
  440. /// @}
  441. };
  442. /* /////////////////////////////////////////////////////////////////////////
  443. * Operators
  444. */
  445. template< ss_typename_param_k T
  446. , ss_typename_param_k I
  447. , ss_typename_param_k U
  448. >
  449. inline ss_bool_t operator ==(ref_ptr<T, I, U> const& lhs, ref_ptr<T, I, U> const& rhs)
  450. {
  451. return lhs.equal(rhs);
  452. }
  453. template< ss_typename_param_k T
  454. , ss_typename_param_k I
  455. , ss_typename_param_k U
  456. >
  457. inline ss_bool_t operator !=(ref_ptr<T, I, U> const& lhs, ref_ptr<T, I, U> const& rhs)
  458. {
  459. return !lhs.equal(rhs);
  460. }
  461. /* /////////////////////////////////////////////////////////////////////////
  462. * swapping
  463. */
  464. template< ss_typename_param_k T
  465. , ss_typename_param_k I
  466. , ss_typename_param_k U
  467. >
  468. inline void swap(ref_ptr<T, I, U>& lhs, ref_ptr<T, I, U>& rhs)
  469. {
  470. lhs.swap(rhs);
  471. }
  472. /* /////////////////////////////////////////////////////////////////////////
  473. * Shims
  474. */
  475. /** \brief is_empty shim
  476. *
  477. * \ingroup group__library__smart_pointers
  478. */
  479. template< ss_typename_param_k T
  480. , ss_typename_param_k I /* = T */
  481. , ss_typename_param_k U /* = I */
  482. >
  483. inline ss_bool_t is_empty(ref_ptr<T, I, U> const& p)
  484. {
  485. return NULL == p.get();
  486. }
  487. /** \brief get_ptr shim
  488. *
  489. * \ingroup group__library__smart_pointers
  490. */
  491. template< ss_typename_param_k T
  492. , ss_typename_param_k I /* = T */
  493. , ss_typename_param_k U /* = I */
  494. >
  495. inline T* get_ptr(ref_ptr<T, I, U> const& p)
  496. {
  497. return p.get();
  498. }
  499. /** \brief Insertion operator shim
  500. *
  501. * \ingroup group__library__smart_pointers
  502. */
  503. template< ss_typename_param_k S
  504. , ss_typename_param_k T
  505. , ss_typename_param_k I /* = T */
  506. , ss_typename_param_k U /* = I */
  507. >
  508. inline S& operator <<(S& s, ref_ptr<T, I, U> const& p)
  509. {
  510. return s << *p;
  511. }
  512. /* /////////////////////////////////////////////////////////////////////////
  513. * Unit-testing
  514. */
  515. #ifdef STLSOFT_UNITTEST
  516. # include "./unittest/ref_ptr_unittest_.h"
  517. #endif /* STLSOFT_UNITTEST */
  518. /* ////////////////////////////////////////////////////////////////////// */
  519. #ifndef _STLSOFT_NO_NAMESPACE
  520. } // namespace stlsoft
  521. #endif /* _STLSOFT_NO_NAMESPACE */
  522. /* In the special case of Intel behaving as VC++ 7.0 or earlier on Win32, we
  523. * illegally insert into the std namespace.
  524. */
  525. #if defined(STLSOFT_CF_std_NAMESPACE)
  526. # if ( ( defined(STLSOFT_COMPILER_IS_INTEL) && \
  527. defined(_MSC_VER))) && \
  528. _MSC_VER < 1310
  529. namespace std
  530. {
  531. template< ss_typename_param_k T
  532. , ss_typename_param_k I
  533. , ss_typename_param_k U
  534. >
  535. inline void swap(stlsoft_ns_qual(ref_ptr)<T, I, U>& lhs, stlsoft_ns_qual(ref_ptr)<T, I, U>& rhs)
  536. {
  537. lhs.swap(rhs);
  538. }
  539. } // namespace std
  540. # endif /* INTEL && _MSC_VER < 1310 */
  541. #endif /* STLSOFT_CF_std_NAMESPACE */
  542. /* ////////////////////////////////////////////////////////////////////// */
  543. #endif /* !STLSOFT_INCL_STLSOFT_SMARTPTR_HPP_REF_PTR */
  544. /* ///////////////////////////// end of file //////////////////////////// */