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.

394 lines
12 KiB

  1. /* /////////////////////////////////////////////////////////////////////////
  2. * File: stlsoft/util/options_verifier.hpp
  3. *
  4. * Purpose: Options verification.
  5. *
  6. * Created: 9th November 2004
  7. * Updated: 10th August 2009
  8. *
  9. * Home: http://stlsoft.org/
  10. *
  11. * Copyright (c) 2004-2009, 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/util/options_verifier.hpp
  40. *
  41. * \brief [C++ only] Definition of the stlsoft::options_verifier class
  42. * template
  43. * (\ref group__library__utility "Utility" Library).
  44. */
  45. #ifndef STLSOFT_INCL_STLSOFT_UTIL_HPP_OPTIONS_VERIFIER
  46. #define STLSOFT_INCL_STLSOFT_UTIL_HPP_OPTIONS_VERIFIER
  47. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  48. # define STLSOFT_VER_STLSOFT_UTIL_HPP_OPTIONS_VERIFIER_MAJOR 2
  49. # define STLSOFT_VER_STLSOFT_UTIL_HPP_OPTIONS_VERIFIER_MINOR 0
  50. # define STLSOFT_VER_STLSOFT_UTIL_HPP_OPTIONS_VERIFIER_REVISION 4
  51. # define STLSOFT_VER_STLSOFT_UTIL_HPP_OPTIONS_VERIFIER_EDIT 43
  52. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  53. /* /////////////////////////////////////////////////////////////////////////
  54. * Compatibility
  55. */
  56. /*
  57. [Incompatibilies-start]
  58. STLSOFT_COMPILER_IS_MSVC: _MSC_VER==1300
  59. [Incompatibilies-end]
  60. */
  61. #if defined(STLSOFT_COMPILER_IS_MWERKS) || \
  62. ( defined(STLSOFT_COMPILER_IS_MSVC) && \
  63. _MSC_VER == 1200)
  64. # define STLSOFT_OPTIONS_VERIFIER_REQUIRES_SEPARATE_NS
  65. #endif /* compiler */
  66. /* /////////////////////////////////////////////////////////////////////////
  67. * Includes
  68. */
  69. #ifndef STLSOFT_INCL_STLSOFT_H_STLSOFT
  70. # include <stlsoft/stlsoft.h>
  71. #endif /* !STLSOFT_INCL_STLSOFT_H_STLSOFT */
  72. #if defined(STLSOFT_COMPILER_IS_MSVC) && \
  73. _MSC_VER == 1300
  74. # pragma warning("Inclusion of this header can lead to ambiguities with the sequence operator (comma) with Visual C++ 7.0")
  75. #endif /* compiler */
  76. #ifndef STLSOFT_INCL_STLSOFT_SHIMS_ACCESS_HPP_STRING
  77. # include <stlsoft/shims/access/string.hpp>
  78. #endif /* !STLSOFT_INCL_STLSOFT_SHIMS_ACCESS_HPP_STRING */
  79. #ifndef STLSOFT_INCL_EXCEPTION
  80. # define STLSOFT_INCL_EXCEPTION
  81. # include <exception> // for uncaught_exception
  82. #endif /* !STLSOFT_INCL_EXCEPTION */
  83. #ifndef STLSOFT_INCL_STDEXCEPT
  84. # define STLSOFT_INCL_STDEXCEPT
  85. # include <stdexcept> // for std::runtime_error
  86. #endif /* !STLSOFT_INCL_STDEXCEPT */
  87. #ifdef STLSOFT_UNITTEST
  88. # include <string>
  89. #endif /* STLSOFT_UNITTEST */
  90. /* /////////////////////////////////////////////////////////////////////////
  91. * Namespace
  92. */
  93. #ifndef _STLSOFT_NO_NAMESPACE
  94. namespace stlsoft
  95. {
  96. #endif /* _STLSOFT_NO_NAMESPACE */
  97. /* /////////////////////////////////////////////////////////////////////////
  98. * Classes
  99. */
  100. /** \brief Exception thrown by the options_verifier class template
  101. *
  102. * \ingroup group__library__utility
  103. *
  104. */
  105. class option_verification_exception
  106. : public stlsoft_ns_qual_std(runtime_error)
  107. {
  108. public:
  109. typedef stlsoft_ns_qual_std(runtime_error) parent_class_type;
  110. typedef option_verification_exception class_type;
  111. public:
  112. option_verification_exception(char const* message)
  113. : parent_class_type(message)
  114. {}
  115. #ifdef STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT
  116. template <ss_typename_param_k S>
  117. option_verification_exception(S const& message)
  118. : parent_class_type(stlsoft_ns_qual(c_str_ptr)(message))
  119. {}
  120. #endif /* STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT */
  121. /// Copy constructor
  122. ///
  123. /// \note This has to be provided, to avoid precipitating C4217 with Visual C++
  124. option_verification_exception(class_type const& rhs)
  125. : parent_class_type(rhs)
  126. {}
  127. /// Copy assignment operator
  128. ///
  129. /// \note This has to be provided, to avoid precipitating C4217 with Visual C++
  130. class_type& operator =(class_type const& rhs)
  131. {
  132. parent_class_type::operator =(rhs);
  133. return *this;
  134. }
  135. };
  136. /** \brief Exception policy for options verification
  137. *
  138. * \ingroup group__library__utility
  139. *
  140. */
  141. // [[synesis:class:exception-policy: option_verification_policy]]
  142. struct option_verification_policy
  143. {
  144. public:
  145. /// The thrown type
  146. typedef option_verification_exception thrown_type;
  147. public:
  148. void operator ()(char const* message)
  149. {
  150. STLSOFT_THROW_X(option_verification_exception(message));
  151. }
  152. };
  153. #ifdef STLSOFT_OPTIONS_VERIFIER_REQUIRES_SEPARATE_NS
  154. namespace options_verifier_internal_ns
  155. {
  156. #endif /* STLSOFT_OPTIONS_VERIFIER_REQUIRES_SEPARATE_NS */
  157. /** \brief Verifies that a given variable is equal to one of a set of options
  158. *
  159. * \ingroup group__library__utility
  160. *
  161. */
  162. template< ss_typename_param_k T
  163. , ss_typename_param_k XP = option_verification_policy
  164. >
  165. class options_verifier
  166. #if !defined(STLSOFT_COMPILER_IS_DMC)
  167. : private XP // Inherit, so we can utilise EBO
  168. #else /* ? compiler */
  169. : public XP // Inherit, so we can utilise EBO
  170. #endif /* compiler */
  171. {
  172. public:
  173. typedef T value_type;
  174. typedef XP exception_policy_type;
  175. typedef XP parent_class_type;
  176. typedef options_verifier<T, XP> class_type;
  177. public:
  178. options_verifier(T const& value, char const* failureMessage)
  179. : parent_class_type()
  180. , m_value(value)
  181. , m_failureMessage(failureMessage)
  182. , m_bMatched(false)
  183. {}
  184. options_verifier(T const& value, exception_policy_type policy, char const* failureMessage)
  185. : parent_class_type(policy)
  186. , m_value(value)
  187. , m_failureMessage(failureMessage)
  188. , m_bMatched(false)
  189. {}
  190. options_verifier(class_type const& rhs)
  191. : parent_class_type(rhs)
  192. , m_value(rhs.m_value)
  193. , m_failureMessage(rhs.m_failureMessage)
  194. , m_bMatched(rhs.m_bMatched)
  195. {
  196. rhs.m_bMatched = true;
  197. }
  198. /// Destructor
  199. ///
  200. /// \note The destructor for options_verifier deliberately does not
  201. /// declare a throw() clause because it does indeed throw an exception.
  202. ///
  203. /// If we've not had a match, and we've not currently unwinding
  204. /// from another exception, then we report the failure.
  205. ///
  206. /// \note This requires that options_verifier is *never* used
  207. /// inside a catch block.
  208. ///
  209. /// \note CodeWarrior doesn't support uncaught_exception, so we
  210. /// have a potentially nasty situation whereby an options_verifier
  211. /// could be being destroyed as part of the cleanup of another
  212. /// exception. However, since options_verifier should never be
  213. /// created other than by calling verify_options(), this means that
  214. /// instances will always be temporary, which means that they'll
  215. /// never exist for long enough for an external exception to enter
  216. /// their lifetime. This is another reason why the failure message
  217. /// is char const*, and not string, and why m_value is a reference,
  218. /// not a value.
  219. ~options_verifier()
  220. {
  221. if( !m_bMatched &&
  222. # if defined(STLSOFT_COMPILER_IS_MWERKS)
  223. 1)
  224. # else /* ? compiler */
  225. !::std::uncaught_exception())
  226. # endif /* compiler */
  227. {
  228. exception_policy_type &policy = *this;
  229. policy(m_failureMessage);
  230. }
  231. }
  232. public:
  233. template <ss_typename_param_k U>
  234. class_type& test(U const& u)
  235. {
  236. if( !m_bMatched &&
  237. m_value == u)
  238. {
  239. m_bMatched = true;
  240. }
  241. return *this;
  242. }
  243. private:
  244. T const &m_value;
  245. char const* const m_failureMessage;
  246. ss_mutable_k bool m_bMatched;
  247. private:
  248. class_type& operator =(class_type const&);
  249. };
  250. #ifdef STLSOFT_OPTIONS_VERIFIER_REQUIRES_SEPARATE_NS
  251. } // namespace options_verifier_internal_ns
  252. using options_verifier_internal_ns::options_verifier;
  253. #endif /* STLSOFT_OPTIONS_VERIFIER_REQUIRES_SEPARATE_NS */
  254. template<ss_typename_param_k T>
  255. options_verifier<T> verify_options(T const& value, char const* failureMessage)
  256. {
  257. return options_verifier<T>(value, failureMessage);
  258. }
  259. template< ss_typename_param_k T
  260. , ss_typename_param_k XP
  261. >
  262. options_verifier<T, XP> verify_options(T const& value, XP const& policy, char const* failureMessage)
  263. {
  264. return options_verifier<T, XP>(value, policy, failureMessage);
  265. }
  266. #ifdef STLSOFT_OPTIONS_VERIFIER_REQUIRES_SEPARATE_NS
  267. namespace options_verifier_internal_ns
  268. {
  269. #endif /* STLSOFT_OPTIONS_VERIFIER_REQUIRES_SEPARATE_NS */
  270. template< ss_typename_param_k T
  271. , ss_typename_param_k XP
  272. , ss_typename_param_k U
  273. >
  274. inline options_verifier<T, XP>& operator ,(options_verifier<T, XP> &ov, U const& u)
  275. {
  276. return ov.test(u);
  277. }
  278. #if 1
  279. /** \brief Acts as a temporary reference to the options_verifier
  280. *
  281. * \ingroup group__library__utility
  282. *
  283. */
  284. template< ss_typename_param_k T
  285. , ss_typename_param_k U
  286. >
  287. class options_verifier_comparison_ref
  288. {
  289. public:
  290. typedef options_verifier<T> verifier_type;
  291. typedef options_verifier_comparison_ref<T, U> class_type;
  292. public:
  293. options_verifier_comparison_ref(verifier_type *verifier)
  294. : m_verifier(verifier)
  295. {}
  296. options_verifier_comparison_ref(class_type const& rhs)
  297. : m_verifier(rhs.m_verifier)
  298. {}
  299. public:
  300. class_type& test(U const& u)
  301. {
  302. m_verifier->test(u);
  303. return *this;
  304. }
  305. private:
  306. verifier_type *m_verifier;
  307. };
  308. template< ss_typename_param_k T
  309. , ss_typename_param_k U
  310. >
  311. inline options_verifier_comparison_ref<T, U>& operator ==(options_verifier<T> const& ov, U const& u)
  312. {
  313. // NOTE: Have to declare the ov as const, and const_cast it. That's valid because
  314. // an options_verifier will only be used in one way, but it's still a bit yuck.
  315. options_verifier_comparison_ref<T, U> ovcr(const_cast<options_verifier<T>*>(&ov));
  316. return ovcr.test(u);
  317. }
  318. template< ss_typename_param_k T
  319. , ss_typename_param_k U1
  320. , ss_typename_param_k U2
  321. >
  322. inline options_verifier_comparison_ref<T, U1>& operator ||(options_verifier_comparison_ref<T, U1> &ov, U2 const& u)
  323. {
  324. return ov.test(u);
  325. }
  326. #endif /* 0 */
  327. #ifdef STLSOFT_OPTIONS_VERIFIER_REQUIRES_SEPARATE_NS
  328. } // namespace options_verifier_internal_ns
  329. #endif /* STLSOFT_OPTIONS_VERIFIER_REQUIRES_SEPARATE_NS */
  330. ////////////////////////////////////////////////////////////////////////////
  331. // Unit-testing
  332. #ifdef STLSOFT_UNITTEST
  333. # include "./unittest/options_verifier_unittest_.h"
  334. #endif /* STLSOFT_UNITTEST */
  335. /* ////////////////////////////////////////////////////////////////////// */
  336. #ifndef _STLSOFT_NO_NAMESPACE
  337. } // namespace stlsoft
  338. #endif /* _STLSOFT_NO_NAMESPACE */
  339. /* ////////////////////////////////////////////////////////////////////// */
  340. #endif /* !STLSOFT_INCL_STLSOFT_UTIL_HPP_OPTIONS_VERIFIER */
  341. /* ///////////////////////////// end of file //////////////////////////// */