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.

578 lines
17 KiB

  1. /* /////////////////////////////////////////////////////////////////////////
  2. * File: comstl/collections/enumeration_policies.hpp
  3. *
  4. * Purpose: Policies for enumerator interface handling.
  5. *
  6. * Created: 20th December 2003
  7. * Updated: 5th March 2011
  8. *
  9. * Home: http://stlsoft.org/
  10. *
  11. * Copyright (c) 2003-2011, 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 comstl/collections/enumeration_policies.hpp
  40. *
  41. * \brief [C++ only] Policies for enumerator interface handling
  42. * (\ref group__library__collections "Collections" Library).
  43. */
  44. #ifndef COMSTL_INCL_COMSTL_COLLECTIONS_HPP_ENUMERATION_POLICIES
  45. #define COMSTL_INCL_COMSTL_COLLECTIONS_HPP_ENUMERATION_POLICIES
  46. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  47. # define COMSTL_VER_COMSTL_COLLECTIONS_HPP_ENUMERATION_POLICIES_MAJOR 6
  48. # define COMSTL_VER_COMSTL_COLLECTIONS_HPP_ENUMERATION_POLICIES_MINOR 1
  49. # define COMSTL_VER_COMSTL_COLLECTIONS_HPP_ENUMERATION_POLICIES_REVISION 6
  50. # define COMSTL_VER_COMSTL_COLLECTIONS_HPP_ENUMERATION_POLICIES_EDIT 53
  51. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  52. /* /////////////////////////////////////////////////////////////////////////
  53. * Compatibility
  54. */
  55. /*
  56. [Incompatibilies-start]
  57. STLSOFT_COMPILER_IS_WATCOM:
  58. [Incompatibilies-end]
  59. */
  60. /* /////////////////////////////////////////////////////////////////////////
  61. * Includes
  62. */
  63. #ifndef COMSTL_INCL_COMSTL_H_COMSTL
  64. # include <comstl/comstl.h>
  65. #endif /* !COMSTL_INCL_COMSTL_H_COMSTL */
  66. #ifndef STLSOFT_INCL_STLSOFT_UTIL_STD_HPP_ITERATOR_HELPER
  67. # include <stlsoft/util/std/iterator_helper.hpp>
  68. #endif /* !STLSOFT_INCL_STLSOFT_UTIL_STD_HPP_ITERATOR_HELPER */
  69. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  70. # ifndef COMSTL_INCL_COMSTL_ERROR_HPP_EXCEPTIONS
  71. # include <comstl/error/exceptions.hpp>
  72. # endif /* !COMSTL_INCL_COMSTL_ERROR_HPP_EXCEPTIONS */
  73. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  74. /* /////////////////////////////////////////////////////////////////////////
  75. * Namespace
  76. */
  77. #ifndef _COMSTL_NO_NAMESPACE
  78. # if defined(_STLSOFT_NO_NAMESPACE) || \
  79. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  80. /* There is no stlsoft namespace, so must define ::comstl */
  81. namespace comstl
  82. {
  83. # else
  84. /* Define stlsoft::comstl_project */
  85. namespace stlsoft
  86. {
  87. namespace comstl_project
  88. {
  89. # endif /* _STLSOFT_NO_NAMESPACE */
  90. #endif /* !_COMSTL_NO_NAMESPACE */
  91. /* /////////////////////////////////////////////////////////////////////////
  92. * Classes
  93. */
  94. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  95. /** \brief Exception class thrown when Clone() method fails
  96. *
  97. * \ingroup group__library__collections
  98. */
  99. // [[synesis:class:exception: comstl::clone_failure]]
  100. class clone_failure
  101. : public com_exception
  102. {
  103. /// \name Member Types
  104. /// @{
  105. public:
  106. /// \brief The parent class type
  107. typedef com_exception parent_class_type;
  108. /// \brief The type of this class
  109. typedef clone_failure class_type;
  110. /// @}
  111. /// \name Construction
  112. /// @{
  113. public:
  114. /// \brief Constructs an instance from the given HRESULT code
  115. ss_explicit_k clone_failure(HRESULT hr)
  116. : parent_class_type(hr)
  117. {}
  118. /// @}
  119. /// \name Accessors
  120. /// @{
  121. public:
  122. /// \brief Returns a human-readable description of the exceptional condition
  123. #if defined(STLSOFT_COMPILER_IS_DMC)
  124. char const* what() const throw()
  125. #else /* ? compiler */
  126. char const* what() const stlsoft_throw_0()
  127. #endif /* compiler */
  128. {
  129. return "Request to clone enumerator failed";
  130. }
  131. /// @}
  132. /// \name Not to be implemented
  133. /// @{
  134. private:
  135. class_type& operator =(class_type const&);
  136. /// @}
  137. };
  138. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  139. /** \brief Policy tag type that indicates an enumerator's Clone() method
  140. * will fail.
  141. *
  142. * \ingroup group__library__collections
  143. */
  144. struct noncloneable_enumerator_tag
  145. {};
  146. /** \brief Policy tag type that indicates an enumerator's Clone() method
  147. * will succeed.
  148. *
  149. * \ingroup group__library__collections
  150. */
  151. struct cloneable_enumerator_tag
  152. {};
  153. /** \brief Policy tag type that indicates an enumerator's Clone() method
  154. * will succeed, and return an enumerator that will provide the same
  155. * sequence of items as the source instance.
  156. *
  157. * \ingroup group__library__collections
  158. */
  159. struct repeatable_enumerator_tag
  160. : public cloneable_enumerator_tag
  161. {};
  162. /** \brief Policy type that causes COM enumerator cloning according the STL Input Iterator concept
  163. *
  164. * \ingroup group__library__collections
  165. *
  166. * \param I The enumeration interface
  167. */
  168. template<ss_typename_param_k I>
  169. struct input_cloning_policy
  170. : public noncloneable_enumerator_tag
  171. {
  172. public:
  173. typedef I interface_type;
  174. typedef interface_type* value_type;
  175. typedef comstl_ns_qual_std(input_iterator_tag) iterator_tag_type;
  176. public:
  177. /// \brief Gets a working "copy" of the given enumerator root
  178. ///
  179. /// \remarks For this policy, this simply calls AddRef()
  180. static interface_type *get_working_instance(interface_type *root)
  181. {
  182. COMSTL_ASSERT(NULL != root);
  183. root->AddRef();
  184. return root;
  185. }
  186. /// \brief "Clones" the given COM enumerator interface according to the Input Iterator concept
  187. static interface_type *share(interface_type *src)
  188. {
  189. COMSTL_ASSERT(NULL != src);
  190. src->AddRef();
  191. return src;
  192. }
  193. static cs_bool_t clone(interface_type *src, interface_type **pdest)
  194. {
  195. COMSTL_ASSERT(NULL != src);
  196. COMSTL_ASSERT(NULL != pdest);
  197. STLSOFT_SUPPRESS_UNUSED(src);
  198. *pdest = NULL;
  199. return false;
  200. }
  201. };
  202. /** \brief Policy type that causes COM enumerator cloning according the STL Input Iterator concept
  203. *
  204. * \ingroup group__library__collections
  205. *
  206. * \param I The enumeration interface
  207. */
  208. template<ss_typename_param_k I>
  209. struct cloneable_cloning_policy
  210. : public cloneable_enumerator_tag
  211. {
  212. public:
  213. typedef I interface_type;
  214. typedef interface_type* value_type;
  215. typedef comstl_ns_qual_std(input_iterator_tag) iterator_tag_type;
  216. public:
  217. /// \brief Gets a working "copy" of the given enumerator root
  218. ///
  219. /// \remarks For this policy, this calls Clone(), and returns NULL
  220. /// if that fails.
  221. static interface_type *get_working_instance(interface_type *root)
  222. {
  223. COMSTL_ASSERT(NULL != root);
  224. interface_type *ret;
  225. HRESULT hr = const_cast<interface_type*>(root)->Clone(&ret);
  226. if(FAILED(hr))
  227. {
  228. ret = NULL;
  229. }
  230. return ret;
  231. }
  232. static interface_type *share(interface_type *src)
  233. {
  234. COMSTL_ASSERT(NULL != src);
  235. interface_type *ret;
  236. HRESULT hr = const_cast<interface_type*>(src)->Clone(&ret);
  237. if(FAILED(hr))
  238. {
  239. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  240. STLSOFT_THROW_X(clone_failure(hr));
  241. #else /* ? STLSOFT_CF_EXCEPTION_SUPPORT */
  242. ret = NULL;
  243. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  244. }
  245. return ret;
  246. }
  247. static cs_bool_t clone(interface_type *src, interface_type **pdest)
  248. {
  249. COMSTL_ASSERT(NULL != src);
  250. COMSTL_ASSERT(NULL != pdest);
  251. *pdest = share(src);
  252. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  253. COMSTL_ASSERT(NULL != *pdest);
  254. return true;
  255. #else /* ? STLSOFT_CF_EXCEPTION_SUPPORT */
  256. return NULL != *pdest;
  257. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  258. }
  259. };
  260. /** \brief Policy type that causes COM enumerator cloning according the STL Forward Iterator concept
  261. *
  262. * \ingroup group__library__collections
  263. *
  264. * \param I The enumeration interface
  265. */
  266. template<ss_typename_param_k I>
  267. struct forward_cloning_policy
  268. : public repeatable_enumerator_tag
  269. {
  270. public:
  271. typedef I interface_type;
  272. typedef interface_type* value_type;
  273. typedef comstl_ns_qual_std(forward_iterator_tag) iterator_tag_type;
  274. public:
  275. /// \brief Gets a working "copy" of the given enumerator root
  276. ///
  277. /// \remarks For this policy, this calls Clone(), and throws an
  278. /// instance of comstl::clone_failure if that fails (or returns
  279. /// NULL if exception support is disabled).
  280. static interface_type *get_working_instance(interface_type *root)
  281. {
  282. COMSTL_ASSERT(NULL != root);
  283. interface_type *ret;
  284. HRESULT hr = const_cast<interface_type*>(root)->Clone(&ret);
  285. if(FAILED(hr))
  286. {
  287. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  288. STLSOFT_THROW_X(clone_failure(hr));
  289. #else /* ? STLSOFT_CF_EXCEPTION_SUPPORT */
  290. ret = NULL;
  291. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  292. }
  293. return ret;
  294. }
  295. /// \brief "Clones" the given COM enumerator interface according to the Forward Iterator concept
  296. static interface_type *share(interface_type *src)
  297. {
  298. COMSTL_ASSERT(NULL != src);
  299. interface_type *ret;
  300. HRESULT hr = const_cast<interface_type*>(src)->Clone(&ret);
  301. if(FAILED(hr))
  302. {
  303. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  304. STLSOFT_THROW_X(clone_failure(hr));
  305. #else /* ? STLSOFT_CF_EXCEPTION_SUPPORT */
  306. ret = NULL;
  307. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  308. }
  309. return ret;
  310. }
  311. static cs_bool_t clone(interface_type *src, interface_type **pdest)
  312. {
  313. COMSTL_ASSERT(NULL != src);
  314. COMSTL_ASSERT(NULL != pdest);
  315. *pdest = share(src);
  316. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  317. COMSTL_ASSERT(NULL != *pdest);
  318. return true;
  319. #else /* ? STLSOFT_CF_EXCEPTION_SUPPORT */
  320. return NULL != *pdest;
  321. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  322. }
  323. };
  324. /** \brief Adapts a value policy to a function class based interface
  325. *
  326. * \ingroup group__library__collections
  327. *
  328. * \param P The value policy (e.g. BSTR_policy, VARIANT_policy, FORMATETC_policy)
  329. */
  330. template <ss_typename_param_k P>
  331. struct value_policy_adaptor
  332. : public P
  333. {
  334. public:
  335. typedef ss_typename_type_k P::value_type value_type;
  336. public:
  337. /// \brief The initialisation function class
  338. struct init_element
  339. {
  340. /// The function call operator, which causes the value to be initialised
  341. void operator ()(value_type &v) const
  342. {
  343. P::init(&v);
  344. }
  345. };
  346. /// \brief The copy function class
  347. struct copy_element
  348. {
  349. /// The function call operator, which causes the destination to be copied from the source
  350. void operator ()(value_type &dest, value_type const& src) const
  351. {
  352. P::copy(&dest, &src);
  353. }
  354. };
  355. /// \brief The clear function class
  356. struct clear_element
  357. {
  358. /// The function call operator, which causes the value to be cleared
  359. void operator ()(value_type &v) const
  360. {
  361. P::clear(&v);
  362. }
  363. };
  364. };
  365. /** \brief [DEPRECATED] Adapts a value policy to a function class based interface
  366. *
  367. * \deprecated Equivalent to value_policy_adaptor
  368. *
  369. * \ingroup group__library__collections
  370. */
  371. template <ss_typename_param_k P>
  372. struct policy_adaptor
  373. : public value_policy_adaptor<P>
  374. {
  375. public:
  376. typedef ss_typename_type_k P::value_type value_type;
  377. };
  378. /** \brief Acquires an enumerator from a collection assuming _NewEnum property
  379. *
  380. * \ingroup group__library__collections
  381. *
  382. * \remarks Invokes the the get__NewEnum() method
  383. */
  384. template <ss_typename_param_k CI>
  385. struct new_enum_property_policy
  386. {
  387. public:
  388. typedef CI collection_interface;
  389. public:
  390. static HRESULT acquire(collection_interface *pcoll, LPUNKNOWN *ppunkEnum)
  391. {
  392. COMSTL_ASSERT(NULL != pcoll);
  393. COMSTL_ASSERT(NULL != ppunkEnum);
  394. // If the compiler complains here that your interface does not have the
  395. // get__NewEnum method, then:
  396. //
  397. // - you're passing a pure IDispatch interface, so you need to use
  398. // new_enum_by_dispid_policy
  399. // - you're passing a collection interface that defines _NeWEnum as a
  400. // method, so you need to use new_enum_method_policy
  401. // - you're passing the wrong interface. Check your code to ensure
  402. // you've not used the wrong interface to specialise
  403. // comstl::collection_sequence.
  404. return pcoll->get__NewEnum(ppunkEnum);
  405. }
  406. };
  407. /** \brief Acquires an enumerator from a collection assuming _NewEnum method
  408. *
  409. * \ingroup group__library__collections
  410. *
  411. * \remarks Invokes the the _NewEnum() method
  412. */
  413. template <ss_typename_param_k CI>
  414. struct new_enum_method_policy
  415. {
  416. public:
  417. typedef CI collection_interface;
  418. public:
  419. static HRESULT acquire(collection_interface *pcoll, LPUNKNOWN *ppunkEnum)
  420. {
  421. COMSTL_ASSERT(NULL != pcoll);
  422. COMSTL_ASSERT(NULL != ppunkEnum);
  423. return pcoll->_NewEnum(ppunkEnum);
  424. }
  425. };
  426. /** \brief Acquires an enumerator from a collection by looking up the DISPID_NEWENUM on the collection's IDispatch interface
  427. *
  428. * \ingroup group__library__collections
  429. *
  430. * \remarks Calls IDispatch::Invoke(DISPID_NEWENUM, . . . , DISPATCH_METHOD | DISPATCH_PROPERTYGET, . . . );
  431. */
  432. template <ss_typename_param_k CI>
  433. struct new_enum_by_dispid_policy
  434. {
  435. public:
  436. typedef CI collection_interface;
  437. public:
  438. static HRESULT acquire(collection_interface *pcoll, LPUNKNOWN *ppunkEnum)
  439. {
  440. COMSTL_ASSERT(NULL != pcoll);
  441. COMSTL_ASSERT(NULL != ppunkEnum);
  442. LPDISPATCH pdisp;
  443. HRESULT hr = pcoll->QueryInterface(IID_IDispatch, reinterpret_cast<void**>(&pdisp));
  444. if(SUCCEEDED(hr))
  445. {
  446. DISPPARAMS params;
  447. UINT argErrIndex;
  448. VARIANT result;
  449. ::memset(&params, 0, sizeof(params));
  450. ::VariantInit(&result);
  451. hr = pdisp->Invoke( DISPID_NEWENUM
  452. , IID_NULL
  453. , LOCALE_USER_DEFAULT
  454. , DISPATCH_METHOD | DISPATCH_PROPERTYGET
  455. , &params
  456. , &result
  457. , NULL
  458. , &argErrIndex);
  459. pdisp->Release();
  460. if(SUCCEEDED(hr))
  461. {
  462. hr = ::VariantChangeType(&result, &result, 0, VT_UNKNOWN);
  463. if(SUCCEEDED(hr))
  464. {
  465. if(NULL == result.punkVal)
  466. {
  467. hr = E_UNEXPECTED;
  468. }
  469. else
  470. {
  471. *ppunkEnum = result.punkVal;
  472. (*ppunkEnum)->AddRef();
  473. }
  474. }
  475. ::VariantClear(&result);
  476. }
  477. }
  478. return hr;
  479. }
  480. };
  481. /* ////////////////////////////////////////////////////////////////////// */
  482. #ifndef _COMSTL_NO_NAMESPACE
  483. # if defined(_STLSOFT_NO_NAMESPACE) || \
  484. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  485. } // namespace comstl
  486. # else
  487. } // namespace stlsoft::comstl_project
  488. } // namespace stlsoft
  489. # endif /* _STLSOFT_NO_NAMESPACE */
  490. #endif /* !_COMSTL_NO_NAMESPACE */
  491. /* ////////////////////////////////////////////////////////////////////// */
  492. #endif /* !COMSTL_INCL_COMSTL_COLLECTIONS_HPP_ENUMERATION_POLICIES */
  493. /* ///////////////////////////// end of file //////////////////////////// */