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.

920 lines
30 KiB

  1. /* /////////////////////////////////////////////////////////////////////////
  2. * File: stlsoft/smartptr/scoped_handle.hpp (evolved from MLResPtr.h, ::SynesisStd)
  3. *
  4. * Purpose: scoped_handle - parameterisable RAII class for arbitrary
  5. * resource types.
  6. *
  7. * Created: 1st November 1994
  8. * Updated: 10th August 2009
  9. *
  10. * Thanks to: Adi Shavit, for requesting the indirect functionality
  11. *
  12. * Home: http://stlsoft.org/
  13. *
  14. * Copyright (c) 1994-2009, Matthew Wilson and Synesis Software
  15. * All rights reserved.
  16. *
  17. * Redistribution and use in source and binary forms, with or without
  18. * modification, are permitted provided that the following conditions are met:
  19. *
  20. * - Redistributions of source code must retain the above copyright notice, this
  21. * list of conditions and the following disclaimer.
  22. * - Redistributions in binary form must reproduce the above copyright notice,
  23. * this list of conditions and the following disclaimer in the documentation
  24. * and/or other materials provided with the distribution.
  25. * - Neither the name(s) of Matthew Wilson and Synesis Software nor the names of
  26. * any contributors may be used to endorse or promote products derived from
  27. * this software without specific prior written permission.
  28. *
  29. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  30. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  31. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  32. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  33. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  34. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  35. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  36. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  37. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  38. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  39. * POSSIBILITY OF SUCH DAMAGE.
  40. *
  41. * ////////////////////////////////////////////////////////////////////// */
  42. /** \file stlsoft/smartptr/scoped_handle.hpp
  43. *
  44. * \brief [C++ only] Definition of the stlsoft::scoped_handle smart
  45. * pointer class template
  46. * (\ref group__library__smart_pointers "Smart Pointers" Library).
  47. */
  48. #ifndef STLSOFT_INCL_STLSOFT_SMARTPTR_HPP_SCOPED_HANDLE
  49. #define STLSOFT_INCL_STLSOFT_SMARTPTR_HPP_SCOPED_HANDLE
  50. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  51. # define STLSOFT_VER_STLSOFT_SMARTPTR_HPP_SCOPED_HANDLE_MAJOR 5
  52. # define STLSOFT_VER_STLSOFT_SMARTPTR_HPP_SCOPED_HANDLE_MINOR 4
  53. # define STLSOFT_VER_STLSOFT_SMARTPTR_HPP_SCOPED_HANDLE_REVISION 3
  54. # define STLSOFT_VER_STLSOFT_SMARTPTR_HPP_SCOPED_HANDLE_EDIT 667
  55. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  56. /* /////////////////////////////////////////////////////////////////////////
  57. * Includes
  58. */
  59. #ifndef STLSOFT_INCL_STLSOFT_H_STLSOFT
  60. # include <stlsoft/stlsoft.h>
  61. #endif /* !STLSOFT_INCL_STLSOFT_H_STLSOFT */
  62. #if defined(STLSOFT_COMPILER_IS_BORLAND)
  63. # include <stlsoft/smartptr/scoped_handle_borland_.hpp>
  64. #else /* ? compiler */
  65. /* /////////////////////////////////////////////////////////////////////////
  66. * Compiler warnings
  67. */
  68. #if defined(STLSOFT_COMPILER_IS_MSVC) && \
  69. _MSC_VER >= 1400
  70. # pragma warning(push)
  71. # pragma warning(disable : 4191)
  72. #endif /* compiler */
  73. /* /////////////////////////////////////////////////////////////////////////
  74. * Namespace
  75. */
  76. #ifndef _STLSOFT_NO_NAMESPACE
  77. namespace stlsoft
  78. {
  79. #endif /* _STLSOFT_NO_NAMESPACE */
  80. /* /////////////////////////////////////////////////////////////////////////
  81. * Classes
  82. */
  83. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  84. template <ss_typename_param_k H>
  85. struct H_holder
  86. {
  87. /// \name Member Types
  88. /// @{
  89. public:
  90. typedef H resource_type;
  91. typedef H handle_type;
  92. typedef H_holder<H> class_type;
  93. /// @}
  94. /// \name Construction
  95. /// @{
  96. public:
  97. H_holder(H h)
  98. : bPointer(false)
  99. {
  100. this->u.h = h;
  101. }
  102. H_holder(H* ph)
  103. : bPointer(true)
  104. {
  105. this->u.ph = ph;
  106. }
  107. /// @}
  108. /// \name Operations
  109. /// @{
  110. public:
  111. H get() const
  112. {
  113. return bPointer ? *u.ph : u.h;
  114. }
  115. void set(H h)
  116. {
  117. (bPointer ? *u.ph : u.h) = h;
  118. }
  119. /// @}
  120. /// \name Member Variables
  121. /// @{
  122. public:
  123. union
  124. {
  125. H h;
  126. H* ph;
  127. } u;
  128. const bool bPointer;
  129. /// @}
  130. private:
  131. H_holder(class_type const&);
  132. class_type& operator =(class_type const&);
  133. };
  134. # ifdef STLSOFT_CF_CDECL_SUPPORTED
  135. template< ss_typename_param_k H
  136. , ss_typename_param_k R
  137. >
  138. struct function_translator_cdecl
  139. {
  140. private:
  141. typedef void (STLSOFT_CDECL* degenerate_function_type)(); // C++-98; 5.2.10;6
  142. public:
  143. typedef R (STLSOFT_CDECL* function_type)(H);
  144. typedef R (STLSOFT_CDECL* indirect_function_type)(H*);
  145. typedef H_holder<H> holder_type;
  146. static void translate(holder_type& h, degenerate_function_type pv)
  147. {
  148. function_type fn = reinterpret_cast<function_type>(pv);
  149. STLSOFT_ASSERT(!h.bPointer);
  150. STLSOFT_MESSAGE_ASSERT("function pointer must not be NULL", NULL != fn);
  151. fn(h.u.h);
  152. }
  153. static void translate_indirect(holder_type& h, degenerate_function_type pv)
  154. {
  155. indirect_function_type fn = reinterpret_cast<indirect_function_type>(pv);
  156. STLSOFT_ASSERT(h.bPointer);
  157. STLSOFT_MESSAGE_ASSERT("function pointer must not be NULL", NULL != fn);
  158. fn(h.u.ph);
  159. }
  160. };
  161. # endif /* STLSOFT_CF_CDECL_SUPPORTED */
  162. # ifdef STLSOFT_CF_FASTCALL_SUPPORTED
  163. template< ss_typename_param_k H
  164. , ss_typename_param_k R
  165. >
  166. struct function_translator_fastcall
  167. {
  168. private:
  169. typedef void (STLSOFT_CDECL* degenerate_function_type)();
  170. public:
  171. typedef R (STLSOFT_FASTCALL* function_type)(H);
  172. typedef R (STLSOFT_FASTCALL* indirect_function_type)(H*);
  173. typedef H_holder<H> holder_type;
  174. static void translate(holder_type& h, degenerate_function_type pv)
  175. {
  176. function_type fn = reinterpret_cast<function_type>(pv);
  177. STLSOFT_ASSERT(!h.bPointer);
  178. STLSOFT_MESSAGE_ASSERT("function pointer must not be NULL", NULL != fn);
  179. fn(h.u.h);
  180. }
  181. static void translate_indirect(holder_type& h, degenerate_function_type pv)
  182. {
  183. indirect_function_type fn = reinterpret_cast<indirect_function_type>(pv);
  184. STLSOFT_ASSERT(h.bPointer);
  185. STLSOFT_MESSAGE_ASSERT("function pointer must not be NULL", NULL != fn);
  186. fn(h.u.ph);
  187. }
  188. };
  189. # endif /* STLSOFT_CF_FASTCALL_SUPPORTED */
  190. # ifdef STLSOFT_CF_STDCALL_SUPPORTED
  191. template< ss_typename_param_k H
  192. , ss_typename_param_k R
  193. >
  194. struct function_translator_stdcall
  195. {
  196. private:
  197. typedef void (STLSOFT_CDECL* degenerate_function_type)();
  198. public:
  199. typedef R (STLSOFT_STDCALL* function_type)(H);
  200. typedef R (STLSOFT_STDCALL* indirect_function_type)(H*);
  201. typedef H_holder<H> holder_type;
  202. static void translate(holder_type& h, degenerate_function_type pv)
  203. {
  204. function_type fn = reinterpret_cast<function_type>(pv);
  205. STLSOFT_ASSERT(!h.bPointer);
  206. STLSOFT_MESSAGE_ASSERT("function pointer must not be NULL", NULL != fn);
  207. fn(h.u.h);
  208. }
  209. static void translate_indirect(holder_type& h, degenerate_function_type pv)
  210. {
  211. indirect_function_type fn = reinterpret_cast<indirect_function_type>(pv);
  212. STLSOFT_ASSERT(h.bPointer);
  213. STLSOFT_MESSAGE_ASSERT("function pointer must not be NULL", NULL != fn);
  214. fn(h.u.ph);
  215. }
  216. };
  217. # endif /* STLSOFT_CF_STDCALL_SUPPORTED */
  218. # ifdef STLSOFT_CF_CDECL_SUPPORTED
  219. template< ss_typename_param_k R
  220. >
  221. struct function_translator_cdecl_void
  222. {
  223. private:
  224. typedef void (STLSOFT_CDECL *degenerate_function_type)(); // C++-98; 5.2.10;6
  225. public:
  226. typedef R (STLSOFT_CDECL *function_type)(void);
  227. static void translate(degenerate_function_type pv)
  228. {
  229. function_type fn = reinterpret_cast<function_type>(pv);
  230. STLSOFT_MESSAGE_ASSERT("function pointer must not be NULL", NULL != fn);
  231. fn();
  232. }
  233. };
  234. # endif /* STLSOFT_CF_CDECL_SUPPORTED */
  235. # ifdef STLSOFT_CF_FASTCALL_SUPPORTED
  236. template< ss_typename_param_k R
  237. >
  238. struct function_translator_fastcall_void
  239. {
  240. private:
  241. typedef void (STLSOFT_CDECL *degenerate_function_type)();
  242. public:
  243. typedef R (STLSOFT_FASTCALL *function_type)(void);
  244. static void translate(degenerate_function_type pv)
  245. {
  246. function_type fn = reinterpret_cast<function_type>(pv);
  247. STLSOFT_MESSAGE_ASSERT("function pointer must not be NULL", NULL != fn);
  248. fn();
  249. }
  250. };
  251. # endif /* STLSOFT_CF_FASTCALL_SUPPORTED */
  252. # ifdef STLSOFT_CF_STDCALL_SUPPORTED
  253. template< ss_typename_param_k R
  254. >
  255. struct function_translator_stdcall_void
  256. {
  257. private:
  258. typedef void (STLSOFT_CDECL *degenerate_function_type)();
  259. public:
  260. typedef R (STLSOFT_STDCALL *function_type)(void);
  261. static void translate(degenerate_function_type pv)
  262. {
  263. function_type fn = reinterpret_cast<function_type>(pv);
  264. STLSOFT_MESSAGE_ASSERT("function pointer must not be NULL", NULL != fn);
  265. fn();
  266. }
  267. };
  268. # endif /* STLSOFT_CF_STDCALL_SUPPORTED */
  269. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  270. /** \brief Provides automated scope-based cleanup of arbitrary resource
  271. * types without any memory allocation required to implement the generic
  272. * support.
  273. *
  274. * \ingroup group__library__smart_pointers
  275. *
  276. * The template is parameterised on the resource type (e.g. FILE*, int, void*)
  277. * and instances are initialised from a resource handle and the address of a
  278. * (single-parameter) cleanup function, as in:
  279. *
  280. \code
  281. ::stlsoft::scoped_handle<void*> h3(::malloc(100), ::free);
  282. \endcode
  283. *
  284. * or:
  285. *
  286. \code
  287. ::stlsoft::scoped_handle<int> h1(::open("file.ext"), ::close);
  288. \endcode
  289. *
  290. * or:
  291. *
  292. \code
  293. FILE* file = ::fopen("file.ext", "r");
  294. ::stlsoft::scoped_handle<FILE*> h2(file, ::fclose);
  295. \endcode
  296. *
  297. * \note This class provides externally-initialised immutable-RAII (see section
  298. * 3.5 of Imperfect C++; http://imperfectcplusplus.com/). The managed resource
  299. * must be provided in the constructor, and the managing instance cannot be set
  300. * to manage another resource. However, there is a nod to convenience in so far
  301. * as there is a detach() method, which can be used to clear the resource from
  302. * the managing instance and return it to the calling context.
  303. */
  304. template<ss_typename_param_k H>
  305. class scoped_handle
  306. {
  307. /// \name Types
  308. /// @{
  309. private:
  310. typedef void (STLSOFT_CDECL* degenerate_function_type)();
  311. typedef H_holder<H> holder_type;
  312. public:
  313. /// \brief The resource type
  314. typedef H resource_type;
  315. /// \brief The handle type
  316. typedef H handle_type;
  317. /// \brief The instantiation of the type
  318. typedef scoped_handle<H> class_type;
  319. /// @}
  320. /// \name Construction
  321. /// @{
  322. public:
  323. #ifdef STLSOFT_CF_CDECL_SUPPORTED
  324. # if !defined(STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT) || \
  325. defined(STLSOFT_CF_MEMBER_TEMPLATE_CTOR_OVERLOAD_DISCRIMINATED)
  326. /// \brief Construct from a resource handle and a clean-up function with void return type
  327. scoped_handle( resource_type h
  328. , void (STLSOFT_CDECL *f)(resource_type)
  329. , resource_type hNull = 0)
  330. : m_hh(h)
  331. , m_hNull(hNull)
  332. , m_tfn(&function_translator_cdecl<H, void>::translate)
  333. , m_fn(reinterpret_cast<degenerate_function_type>(f))
  334. {
  335. STLSOFT_MESSAGE_ASSERT("Precondition violation: cannot initialise with a NULL function pointer", NULL != f);
  336. }
  337. /// \brief Construct from a resource handle and an indirect clean-up function with void return type
  338. scoped_handle( resource_type* ph
  339. , void (STLSOFT_CDECL *f)(resource_type*)
  340. , resource_type hNull = 0)
  341. : m_hh(ph)
  342. , m_hNull(hNull)
  343. , m_tfn(&function_translator_cdecl<H, void>::translate_indirect)
  344. , m_fn(reinterpret_cast<degenerate_function_type>(f))
  345. {
  346. STLSOFT_MESSAGE_ASSERT("Precondition violation: cannot initialise with a NULL function pointer", NULL != f);
  347. }
  348. # endif /* !STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT || STLSOFT_CF_MEMBER_TEMPLATE_CTOR_OVERLOAD_DISCRIMINATED */
  349. # if defined(STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT)
  350. /// \brief Construct from a resource handle and a clean-up function with non-void return type
  351. template <ss_typename_param_k R>
  352. scoped_handle( resource_type h
  353. , R (STLSOFT_CDECL *f)(resource_type)
  354. , resource_type hNull = 0)
  355. : m_hh(h)
  356. , m_hNull(hNull)
  357. , m_tfn(&function_translator_cdecl<H, R>::translate)
  358. , m_fn(reinterpret_cast<degenerate_function_type>(f))
  359. {
  360. STLSOFT_MESSAGE_ASSERT("Precondition violation: cannot initialise with a NULL function pointer", NULL != f);
  361. }
  362. /// \brief Construct from a resource handle and an indirect clean-up function with non-void return type
  363. template <ss_typename_param_k R>
  364. scoped_handle( resource_type* ph
  365. , R (STLSOFT_CDECL *f)(resource_type*)
  366. , resource_type hNull = 0)
  367. : m_hh(ph)
  368. , m_hNull(hNull)
  369. , m_tfn(&function_translator_cdecl<H, R>::translate_indirect)
  370. , m_fn(reinterpret_cast<degenerate_function_type>(f))
  371. {
  372. STLSOFT_MESSAGE_ASSERT("Precondition violation: cannot initialise with a NULL function pointer", NULL != f);
  373. }
  374. # endif /* STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT */
  375. #endif /* STLSOFT_CF_CDECL_SUPPORTED */
  376. #ifdef STLSOFT_CF_FASTCALL_SUPPORTED
  377. # if !defined(STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT) || \
  378. defined(STLSOFT_CF_MEMBER_TEMPLATE_CTOR_OVERLOAD_DISCRIMINATED)
  379. /// \brief Construct from a resource handle and a clean-up "fastcall" function with void return type
  380. scoped_handle( resource_type h
  381. , void (STLSOFT_FASTCALL *f)(resource_type)
  382. , resource_type hNull = 0)
  383. : m_hh(h)
  384. , m_hNull(hNull)
  385. , m_tfn(&function_translator_fastcall<H, void>::translate)
  386. , m_fn(reinterpret_cast<degenerate_function_type>(f))
  387. {
  388. STLSOFT_MESSAGE_ASSERT("Precondition violation: cannot initialise with a NULL function pointer", NULL != f);
  389. }
  390. /// \brief Construct from a resource handle and an indirect clean-up "fastcall" function with void return type
  391. scoped_handle( resource_type h
  392. , void (STLSOFT_FASTCALL *f)(resource_type *)
  393. , resource_type hNull = 0)
  394. : m_hh(h)
  395. , m_hNull(hNull)
  396. , m_tfn(&function_translator_fastcall<H, void>::translate_indirect)
  397. , m_fn(reinterpret_cast<degenerate_function_type>(f))
  398. {
  399. STLSOFT_MESSAGE_ASSERT("Precondition violation: cannot initialise with a NULL function pointer", NULL != f);
  400. }
  401. # endif /* !STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT || STLSOFT_CF_MEMBER_TEMPLATE_CTOR_OVERLOAD_DISCRIMINATED */
  402. # if defined(STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT)
  403. /// \brief Construct from a resource handle and a clean-up "fastcall" function with non-void return type
  404. template <ss_typename_param_k R>
  405. scoped_handle( resource_type h
  406. , R (STLSOFT_FASTCALL *f)(resource_type)
  407. , resource_type hNull = 0)
  408. : m_hh(h)
  409. , m_hNull(hNull)
  410. , m_tfn(&function_translator_fastcall<H, R>::translate)
  411. , m_fn(reinterpret_cast<degenerate_function_type>(f))
  412. {
  413. STLSOFT_MESSAGE_ASSERT("Precondition violation: cannot initialise with a NULL function pointer", NULL != f);
  414. }
  415. /// \brief Construct from a resource handle and an indirect clean-up "fastcall" function with non-void return type
  416. template <ss_typename_param_k R>
  417. scoped_handle( resource_type* ph
  418. , R (STLSOFT_FASTCALL *f)(resource_type*)
  419. , resource_type hNull = 0)
  420. : m_hh(ph)
  421. , m_hNull(hNull)
  422. , m_tfn(&function_translator_fastcall<H, R>::translate_indirect)
  423. , m_fn(reinterpret_cast<degenerate_function_type>(f))
  424. {
  425. STLSOFT_MESSAGE_ASSERT("Precondition violation: cannot initialise with a NULL function pointer", NULL != f);
  426. }
  427. # endif /* STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT */
  428. #endif /* STLSOFT_CF_FASTCALL_SUPPORTED */
  429. #ifdef STLSOFT_CF_STDCALL_SUPPORTED
  430. # if !defined(STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT) || \
  431. defined(STLSOFT_CF_MEMBER_TEMPLATE_CTOR_OVERLOAD_DISCRIMINATED)
  432. /// \brief Construct from a resource handle and a clean-up "stdcall" function with void return type
  433. scoped_handle( resource_type h
  434. , void (STLSOFT_STDCALL *f)(resource_type)
  435. , resource_type hNull = 0)
  436. : m_hh(h)
  437. , m_hNull(hNull)
  438. , m_tfn(&function_translator_stdcall<H, void>::translate)
  439. , m_fn(reinterpret_cast<degenerate_function_type>(f))
  440. {
  441. STLSOFT_MESSAGE_ASSERT("Precondition violation: cannot initialise with a NULL function pointer", NULL != f);
  442. }
  443. /// \brief Construct from a resource handle and an indirect clean-up "stdcall" function with void return type
  444. scoped_handle( resource_type* ph
  445. , void (STLSOFT_STDCALL *f)(resource_type*)
  446. , resource_type hNull = 0)
  447. : m_hh(ph)
  448. , m_hNull(hNull)
  449. , m_tfn(&function_translator_stdcall<H, void>::translate_indirect)
  450. , m_fn(reinterpret_cast<degenerate_function_type>(f))
  451. {
  452. STLSOFT_MESSAGE_ASSERT("Precondition violation: cannot initialise with a NULL function pointer", NULL != f);
  453. }
  454. # endif /* !STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT || STLSOFT_CF_MEMBER_TEMPLATE_CTOR_OVERLOAD_DISCRIMINATED */
  455. # if defined(STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT)
  456. /// \brief Construct from a resource handle and a clean-up "stdcall" function with non-void return type
  457. template <ss_typename_param_k R>
  458. scoped_handle( resource_type h
  459. , R (STLSOFT_STDCALL *f)(resource_type)
  460. , resource_type hNull = 0)
  461. : m_hh(h)
  462. , m_hNull(hNull)
  463. , m_tfn(&function_translator_stdcall<H, R>::translate)
  464. , m_fn(reinterpret_cast<degenerate_function_type>(f))
  465. {
  466. STLSOFT_MESSAGE_ASSERT("Precondition violation: cannot initialise with a NULL function pointer", NULL != f);
  467. }
  468. /// \brief Construct from a resource handle and an indirect clean-up "stdcall" function with non-void return type
  469. template <ss_typename_param_k R>
  470. scoped_handle( resource_type* ph
  471. , R (STLSOFT_STDCALL *f)(resource_type*)
  472. , resource_type hNull = 0)
  473. : m_hh(ph)
  474. , m_hNull(hNull)
  475. , m_tfn(&function_translator_stdcall<H, R>::translate_indirect)
  476. , m_fn(reinterpret_cast<degenerate_function_type>(f))
  477. {
  478. STLSOFT_MESSAGE_ASSERT("Precondition violation: cannot initialise with a NULL function pointer", NULL != f);
  479. }
  480. # endif /* STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT */
  481. #endif /* STLSOFT_CF_STDCALL_SUPPORTED */
  482. /// \brief "Releases" the managed resource.
  483. ///
  484. /// Invokes the cleanup function, unless close() or detach() have
  485. /// already been called
  486. ~scoped_handle()
  487. {
  488. STLSOFT_MESSAGE_ASSERT("Invariant violation: function pointer must not be NULL", NULL != m_fn);
  489. if(!empty())
  490. {
  491. m_tfn(m_hh, m_fn);
  492. }
  493. }
  494. /// @}
  495. /// \name Attributes
  496. /// @{
  497. public:
  498. /// \brief Indicates whether the instance holds a non-"null" resource
  499. bool empty() const
  500. {
  501. STLSOFT_MESSAGE_ASSERT("Invariant violation: function pointer must not be NULL", NULL != m_fn);
  502. return get_null_value_() == m_hh.get();
  503. }
  504. /// @}
  505. /// \name Operations
  506. /// @{
  507. public:
  508. /// \brief Closes the handle immediately
  509. ///
  510. /// \note Calling this method more than once has no effect.
  511. void close()
  512. {
  513. STLSOFT_MESSAGE_ASSERT("Invariant violation: function pointer must not be NULL", NULL != m_fn);
  514. if(!empty())
  515. {
  516. m_tfn(m_hh, m_fn);
  517. m_hh.set(get_null_value_());
  518. }
  519. }
  520. /// \brief Detaches the resource, and returns it to the caller.
  521. ///
  522. /// \remarks Calling this method removes the resource from the managing
  523. /// instance, so it will not be automatically closed.
  524. resource_type detach()
  525. {
  526. STLSOFT_MESSAGE_ASSERT("Invariant violation: function pointer must not be NULL", NULL != m_fn);
  527. resource_type h = m_hh.get();
  528. m_hh.set(get_null_value_());
  529. return h;
  530. }
  531. /// @}
  532. /// \name Accessors
  533. /// @{
  534. public:
  535. /// \brief Provides the bare resource handle to the caller. Does not
  536. /// detach the handle from the managing instance.
  537. ///
  538. /// \deprecated Deprecated in favour of get()
  539. resource_type handle() const
  540. {
  541. #if defined(STLSOFT_COMPILER_IS_WATCOM)
  542. return (resource_type)(m_hh.get());
  543. #else /* ? compiler */
  544. return const_cast<resource_type>(m_hh.get());
  545. #endif /* compiler */
  546. }
  547. /// \brief Provides the bare resource handle to the caller. Does not detach the
  548. /// handle from the managing instance.
  549. resource_type get() const
  550. {
  551. return const_cast<class_type&>(*this).m_hh.get();
  552. }
  553. /// @}
  554. /// \name Implementation
  555. /// @{
  556. private:
  557. resource_type get_null_value_() const
  558. {
  559. return m_hNull;
  560. }
  561. /// @}
  562. /// \name Members
  563. /// @{
  564. private:
  565. holder_type m_hh; //!< The handle to the managed resource
  566. const resource_type m_hNull; //!< The value for the null handle
  567. void (*m_tfn)(holder_type&, degenerate_function_type); //!< The function translator function
  568. degenerate_function_type m_fn; //!< The actual resource release function
  569. /// @}
  570. /// \name Not to be implemented
  571. /// @{
  572. private:
  573. scoped_handle(class_type const&);
  574. class_type& operator =(class_type const&);
  575. /// @}
  576. };
  577. // scoped_handle<void>
  578. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  579. STLSOFT_TEMPLATE_SPECIALISATION
  580. class scoped_handle<void>
  581. {
  582. /// \name Types
  583. /// @{
  584. private:
  585. typedef void (STLSOFT_CDECL *degenerate_function_type)();
  586. public:
  587. /// \brief The resource type
  588. typedef void resource_type;
  589. /// \brief The handle type
  590. typedef void handle_type;
  591. /// \brief The instantiation of the type
  592. typedef scoped_handle<void> class_type;
  593. /// @}
  594. /// \name Construction
  595. /// @{
  596. public:
  597. #ifdef STLSOFT_CF_CDECL_SUPPORTED
  598. # if !defined(STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT) || \
  599. defined(STLSOFT_CF_MEMBER_TEMPLATE_CTOR_OVERLOAD_DISCRIMINATED)
  600. /// \brief Construct from a resource handle and a clean-up function with void return type
  601. scoped_handle( void (STLSOFT_CDECL *f)())
  602. : m_bInvoked(false)
  603. , m_tfn(&function_translator_cdecl_void<void>::translate)
  604. , m_fn(reinterpret_cast<degenerate_function_type>(f))
  605. {
  606. STLSOFT_MESSAGE_ASSERT("Precondition violation: cannot initialise with a NULL function pointer", NULL != f);
  607. }
  608. # endif /* !STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT || STLSOFT_CF_MEMBER_TEMPLATE_CTOR_OVERLOAD_DISCRIMINATED */
  609. # if defined(STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT)
  610. /// \brief Construct from a resource handle and a clean-up function with non-void return type
  611. template <ss_typename_param_k R>
  612. scoped_handle( R (STLSOFT_CDECL *f)())
  613. : m_bInvoked(false)
  614. , m_tfn(&function_translator_cdecl_void<R>::translate)
  615. , m_fn(reinterpret_cast<degenerate_function_type>(f))
  616. {
  617. STLSOFT_MESSAGE_ASSERT("Precondition violation: cannot initialise with a NULL function pointer", NULL != f);
  618. }
  619. # endif /* STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT */
  620. #endif /* STLSOFT_CF_CDECL_SUPPORTED */
  621. #ifdef STLSOFT_CF_FASTCALL_SUPPORTED
  622. # if !defined(STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT) || \
  623. defined(STLSOFT_CF_MEMBER_TEMPLATE_CTOR_OVERLOAD_DISCRIMINATED)
  624. /// \brief Construct from a resource handle and a clean-up "fastcall" function with void return type
  625. scoped_handle( void (STLSOFT_FASTCALL *f)())
  626. : m_bInvoked(false)
  627. , m_tfn(&function_translator_fastcall_void<void>::translate)
  628. , m_fn(reinterpret_cast<degenerate_function_type>(f))
  629. {
  630. STLSOFT_MESSAGE_ASSERT("Precondition violation: cannot initialise with a NULL function pointer", NULL != f);
  631. }
  632. # endif /* !STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT || STLSOFT_CF_MEMBER_TEMPLATE_CTOR_OVERLOAD_DISCRIMINATED */
  633. # if defined(STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT)
  634. /// \brief Construct from a resource handle and a clean-up "fastcall" function with non-void return type
  635. template <ss_typename_param_k R>
  636. scoped_handle( R (STLSOFT_FASTCALL *f)())
  637. : m_bInvoked(false)
  638. , m_tfn(&function_translator_fastcall_void<R>::translate)
  639. , m_fn(reinterpret_cast<degenerate_function_type>(f))
  640. {
  641. STLSOFT_MESSAGE_ASSERT("Precondition violation: cannot initialise with a NULL function pointer", NULL != f);
  642. }
  643. # endif /* STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT */
  644. #endif /* STLSOFT_CF_FASTCALL_SUPPORTED */
  645. #ifdef STLSOFT_CF_STDCALL_SUPPORTED
  646. # if !defined(STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT) || \
  647. defined(STLSOFT_CF_MEMBER_TEMPLATE_CTOR_OVERLOAD_DISCRIMINATED)
  648. /// \brief Construct from a resource handle and a clean-up "stdcall" function with void return type
  649. scoped_handle( void (STLSOFT_STDCALL *f)())
  650. : m_bInvoked(false)
  651. , m_tfn(&function_translator_stdcall_void<void>::translate)
  652. , m_fn(reinterpret_cast<degenerate_function_type>(f))
  653. {
  654. STLSOFT_MESSAGE_ASSERT("Precondition violation: cannot initialise with a NULL function pointer", NULL != f);
  655. }
  656. # endif /* !STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT || STLSOFT_CF_MEMBER_TEMPLATE_CTOR_OVERLOAD_DISCRIMINATED */
  657. # if defined(STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT)
  658. /// \brief Construct from a resource handle and a clean-up "stdcall" function with non-void return type
  659. template <ss_typename_param_k R>
  660. scoped_handle( R (STLSOFT_STDCALL *f)())
  661. : m_bInvoked(false)
  662. , m_tfn(&function_translator_stdcall_void<R>::translate)
  663. , m_fn(reinterpret_cast<degenerate_function_type>(f))
  664. {
  665. STLSOFT_MESSAGE_ASSERT("Precondition violation: cannot initialise with a NULL function pointer", NULL != f);
  666. }
  667. # endif /* STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT */
  668. #endif /* STLSOFT_CF_STDCALL_SUPPORTED */
  669. /// \brief "Releases" the managed resource.
  670. ///
  671. /// Invokes the cleanup function, unless close() or detach() have
  672. /// already been called
  673. ~scoped_handle()
  674. {
  675. close();
  676. }
  677. /// @}
  678. /// \name Attributes
  679. /// @{
  680. public:
  681. /// \brief Indicates whether the instance holds a non-"null" resource
  682. bool empty() const
  683. {
  684. return m_bInvoked;
  685. }
  686. /// @}
  687. /// \name Operations
  688. /// @{
  689. public:
  690. /// \brief Closes the handle immediately
  691. ///
  692. /// \note Calling this method more than once has no effect.
  693. void close()
  694. {
  695. if(!empty())
  696. {
  697. m_tfn(m_fn);
  698. m_bInvoked = true;
  699. }
  700. }
  701. /// \brief Detaches the resource, and returns it to the caller.
  702. ///
  703. /// \remarks Calling this method removes the resource from the managing
  704. /// instance, so it will not be automatically closed.
  705. resource_type detach()
  706. {
  707. m_bInvoked = true;
  708. }
  709. /// @}
  710. /// \name Accessors
  711. /// @{
  712. public:
  713. /// \brief Provides the bare resource handle to the caller. Does not
  714. /// detach the handle from the managing instance.
  715. ///
  716. /// \deprecated Deprecated in favour of get()
  717. resource_type handle() const
  718. {
  719. }
  720. /// \brief Provides the bare resource handle to the caller. Does not detach the
  721. /// handle from the managing instance.
  722. resource_type get() const
  723. {
  724. }
  725. /// @}
  726. /// \name Members
  727. /// @{
  728. private:
  729. ss_bool_t m_bInvoked; //!< Indicates whether the cleanup function has been invoked
  730. void (*m_tfn)(degenerate_function_type); //!< The function translator function
  731. degenerate_function_type m_fn; //!< The actual resource release function
  732. /// @}
  733. /// \name Not to be implemented
  734. /// @{
  735. private:
  736. scoped_handle(class_type const&);
  737. class_type& operator =(class_type const&);
  738. /// @}
  739. };
  740. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  741. /* /////////////////////////////////////////////////////////////////////////
  742. * swapping
  743. */
  744. template< ss_typename_param_k H
  745. >
  746. inline void swap(scoped_handle<H>& lhs, scoped_handle<H>& rhs)
  747. {
  748. lhs.swap(rhs);
  749. }
  750. ////////////////////////////////////////////////////////////////////////////
  751. // Shims
  752. template<ss_typename_param_k H>
  753. #if defined(STLSOFT_COMPILER_IS_WATCOM)
  754. inline H get_handle(scoped_handle<H> const& h)
  755. #else /* ? compiler */
  756. inline ss_typename_type_ret_k scoped_handle<H>::handle_type get_handle(scoped_handle<H> const& h)
  757. #endif /* compiler */
  758. {
  759. return h.get();
  760. }
  761. /* /////////////////////////////////////////////////////////////////////////
  762. * Unit-testing
  763. */
  764. #ifdef STLSOFT_UNITTEST
  765. # include "./unittest/scoped_handle_unittest_.h"
  766. #endif /* STLSOFT_UNITTEST */
  767. /* ////////////////////////////////////////////////////////////////////// */
  768. #ifndef _STLSOFT_NO_NAMESPACE
  769. } // namespace stlsoft
  770. #endif /* _STLSOFT_NO_NAMESPACE */
  771. /* In the special case of Intel behaving as VC++ 7.0 or earlier on Win32, we
  772. * illegally insert into the std namespace.
  773. */
  774. #if defined(STLSOFT_CF_std_NAMESPACE)
  775. # if ( ( defined(STLSOFT_COMPILER_IS_INTEL) && \
  776. defined(_MSC_VER))) && \
  777. _MSC_VER < 1310
  778. namespace std
  779. {
  780. template< ss_typename_param_k H
  781. >
  782. inline void swap(stlsoft_ns_qual(scoped_handle)<H>& lhs, stlsoft_ns_qual(scoped_handle)<H>& rhs)
  783. {
  784. lhs.swap(rhs);
  785. }
  786. } // namespace std
  787. # endif /* INTEL && _MSC_VER < 1310 */
  788. #endif /* STLSOFT_CF_std_NAMESPACE */
  789. /* ////////////////////////////////////////////////////////////////////// */
  790. #endif /* ? compiler */
  791. /* /////////////////////////////////////////////////////////////////////////
  792. * Compiler warnings
  793. */
  794. #if defined(STLSOFT_COMPILER_IS_MSVC) && \
  795. _MSC_VER >= 1400
  796. # pragma warning(pop)
  797. #endif /* compiler */
  798. /* ////////////////////////////////////////////////////////////////////// */
  799. #endif /* !STLSOFT_INCL_STLSOFT_SMARTPTR_HPP_SCOPED_HANDLE */
  800. /* ///////////////////////////// end of file //////////////////////////// */