named_params.hpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  1. // (C) Copyright Gennadiy Rozental 2001.
  2. // Distributed under the Boost Software License, Version 1.0.
  3. // (See accompanying file LICENSE_1_0.txt or copy at
  4. // http://www.boost.org/LICENSE_1_0.txt)
  5. // See http://www.boost.org/libs/test for the library home page.
  6. //
  7. // File : $RCSfile$
  8. //
  9. // Version : $Revision$
  10. //
  11. // Description : named function parameters library
  12. // ***************************************************************************
  13. #ifndef BOOST_TEST_UTILS_NAMED_PARAM
  14. #define BOOST_TEST_UTILS_NAMED_PARAM
  15. // Boost
  16. #include <boost/config.hpp>
  17. #include <boost/detail/workaround.hpp>
  18. // Boost.Test
  19. #include <boost/test/utils/rtti.hpp>
  20. #include <boost/test/utils/assign_op.hpp>
  21. #include <boost/type_traits/remove_reference.hpp>
  22. #include <boost/type_traits/remove_cv.hpp>
  23. #include <boost/test/detail/throw_exception.hpp>
  24. // Boost
  25. #include <boost/mpl/if.hpp>
  26. #include <boost/mpl/or.hpp>
  27. #include <boost/type_traits/is_same.hpp>
  28. #include <boost/type_traits/remove_cv.hpp>
  29. #include <boost/utility/enable_if.hpp>
  30. #include <boost/mpl/bool.hpp>
  31. #include <boost/test/detail/suppress_warnings.hpp>
  32. //____________________________________________________________________________//
  33. namespace boost {
  34. namespace nfp { // named function parameters
  35. // ************************************************************************** //
  36. // ************** forward declarations ************** //
  37. // ************************************************************************** //
  38. template<typename unique_id, bool required> struct keyword;
  39. template<typename T, typename unique_id, bool required = false> struct typed_keyword;
  40. template<typename T, typename unique_id, typename RefType=T&> struct named_parameter;
  41. template<typename NP1,typename NP2> struct named_parameter_combine;
  42. // ************************************************************************** //
  43. // ************** is_named_param_pack ************** //
  44. // ************************************************************************** //
  45. /// is_named_param_pack<T>::value is true if T is parameters pack
  46. template<typename T>
  47. struct is_named_param_pack : public mpl::false_ {};
  48. template<typename T, typename unique_id, typename RefType>
  49. struct is_named_param_pack<named_parameter<T,unique_id,RefType> > : public mpl::true_ {};
  50. template<typename NP, typename Rest>
  51. struct is_named_param_pack<named_parameter_combine<NP,Rest> > : public mpl::true_ {};
  52. // ************************************************************************** //
  53. // ************** param_type ************** //
  54. // ************************************************************************** //
  55. /// param_type<Params,Keyword,Default>::type is the type of the parameter
  56. /// corresponding to the Keyword (if parameter is present) or Default
  57. template<typename NP, typename Keyword, typename DefaultType=void>
  58. struct param_type
  59. : mpl::if_<typename is_same<typename NP::id,typename Keyword::id>::type,
  60. typename remove_cv<typename NP::data_type>::type,
  61. DefaultType> {};
  62. template<typename NP, typename Rest, typename Keyword, typename DefaultType>
  63. struct param_type<named_parameter_combine<NP,Rest>,Keyword,DefaultType>
  64. : mpl::if_<typename is_same<typename NP::id,typename Keyword::id>::type,
  65. typename remove_cv<typename NP::data_type>::type,
  66. typename param_type<Rest,Keyword,DefaultType>::type> {};
  67. // ************************************************************************** //
  68. // ************** has_param ************** //
  69. // ************************************************************************** //
  70. /// has_param<Params,Keyword>::value is true if Params has parameter corresponding
  71. /// to the Keyword
  72. template<typename NP, typename Keyword>
  73. struct has_param : is_same<typename NP::id,typename Keyword::id> {};
  74. template<typename NP, typename Rest, typename Keyword>
  75. struct has_param<named_parameter_combine<NP,Rest>,Keyword>
  76. : mpl::or_<typename is_same<typename NP::id,typename Keyword::id>::type,
  77. typename has_param<Rest,Keyword>::type> {};
  78. // ************************************************************************** //
  79. // ************** access_to_invalid_parameter ************** //
  80. // ************************************************************************** //
  81. namespace nfp_detail {
  82. struct access_to_invalid_parameter {};
  83. //____________________________________________________________________________//
  84. inline void
  85. report_access_to_invalid_parameter( bool v )
  86. {
  87. BOOST_TEST_I_ASSRT( !v, access_to_invalid_parameter() );
  88. }
  89. } // namespace nfp_detail
  90. // ************************************************************************** //
  91. // ************** nil ************** //
  92. // ************************************************************************** //
  93. struct nil {
  94. template<typename T>
  95. #if defined(__GNUC__) || defined(__HP_aCC) || defined(__EDG__) || defined(__SUNPRO_CC)
  96. operator T() const
  97. #else
  98. operator T const&() const
  99. #endif
  100. { nfp_detail::report_access_to_invalid_parameter(true); static T* v = 0; return *v; }
  101. template<typename T>
  102. T any_cast() const
  103. { nfp_detail::report_access_to_invalid_parameter(true); static typename remove_reference<T>::type* v = 0; return *v; }
  104. template<typename Arg1>
  105. nil operator()( Arg1 const& )
  106. { nfp_detail::report_access_to_invalid_parameter(true); return nil(); }
  107. template<typename Arg1,typename Arg2>
  108. nil operator()( Arg1 const&, Arg2 const& )
  109. { nfp_detail::report_access_to_invalid_parameter(true); return nil(); }
  110. template<typename Arg1,typename Arg2,typename Arg3>
  111. nil operator()( Arg1 const&, Arg2 const&, Arg3 const& )
  112. { nfp_detail::report_access_to_invalid_parameter(true); return nil(); }
  113. // Visitation support
  114. template<typename Visitor>
  115. void apply_to( Visitor& /*v*/ ) const {}
  116. static nil& inst() { static nil s_inst; return s_inst; }
  117. private:
  118. nil() {}
  119. };
  120. // ************************************************************************** //
  121. // ************** named_parameter_base ************** //
  122. // ************************************************************************** //
  123. namespace nfp_detail {
  124. template<typename Derived>
  125. struct named_parameter_base {
  126. template<typename NP>
  127. named_parameter_combine<NP,Derived>
  128. operator,( NP const& np ) const { return named_parameter_combine<NP,Derived>( np, *static_cast<Derived const*>(this) ); }
  129. };
  130. } // namespace nfp_detail
  131. // ************************************************************************** //
  132. // ************** named_parameter_combine ************** //
  133. // ************************************************************************** //
  134. template<typename NP, typename Rest = nil>
  135. struct named_parameter_combine
  136. : Rest
  137. , nfp_detail::named_parameter_base<named_parameter_combine<NP,Rest> > {
  138. typedef typename NP::ref_type res_type;
  139. typedef named_parameter_combine<NP,Rest> self_type;
  140. // Constructor
  141. named_parameter_combine( NP const& np, Rest const& r )
  142. : Rest( r )
  143. , m_param( np )
  144. {
  145. }
  146. // Access methods
  147. res_type operator[]( keyword<typename NP::id,true> kw ) const { return m_param[kw]; }
  148. res_type operator[]( keyword<typename NP::id,false> kw ) const { return m_param[kw]; }
  149. using Rest::operator[];
  150. bool has( keyword<typename NP::id,false> kw ) const { return m_param.has( kw ); }
  151. using Rest::has;
  152. void erase( keyword<typename NP::id,false> kw ) const { m_param.erase( kw ); }
  153. using Rest::erase;
  154. using nfp_detail::named_parameter_base<named_parameter_combine<NP,Rest> >::operator,;
  155. // Visitation support
  156. template<typename Visitor>
  157. void apply_to( Visitor& V ) const
  158. {
  159. m_param.apply_to( V );
  160. Rest::apply_to( V );
  161. }
  162. private:
  163. // Data members
  164. NP m_param;
  165. };
  166. // ************************************************************************** //
  167. // ************** named_parameter ************** //
  168. // ************************************************************************** //
  169. template<typename T, typename unique_id, typename RefType>
  170. struct named_parameter
  171. : nfp_detail::named_parameter_base<named_parameter<T,unique_id,RefType> >
  172. {
  173. typedef T data_type;
  174. typedef RefType ref_type;
  175. typedef unique_id id;
  176. // Constructor
  177. explicit named_parameter( ref_type v )
  178. : m_value( v )
  179. , m_erased( false )
  180. {}
  181. named_parameter( named_parameter const& np )
  182. : m_value( np.m_value )
  183. , m_erased( np.m_erased )
  184. {}
  185. // Access methods
  186. ref_type operator[]( keyword<unique_id,true> ) const { return m_erased ? nil::inst().template any_cast<ref_type>() : m_value; }
  187. ref_type operator[]( keyword<unique_id,false> ) const { return m_erased ? nil::inst().template any_cast<ref_type>() : m_value; }
  188. template<typename UnknownId>
  189. nil operator[]( keyword<UnknownId,false> ) const { return nil::inst(); }
  190. bool has( keyword<unique_id,false> ) const { return !m_erased; }
  191. template<typename UnknownId>
  192. bool has( keyword<UnknownId,false> ) const { return false; }
  193. void erase( keyword<unique_id,false> ) const { m_erased = true; }
  194. template<typename UnknownId>
  195. void erase( keyword<UnknownId,false> ) const {}
  196. // Visitation support
  197. template<typename Visitor>
  198. void apply_to( Visitor& V ) const
  199. {
  200. V.set_parameter( rtti::type_id<unique_id>(), m_value );
  201. }
  202. private:
  203. // Data members
  204. ref_type m_value;
  205. mutable bool m_erased;
  206. };
  207. // ************************************************************************** //
  208. // ************** no_params ************** //
  209. // ************************************************************************** //
  210. typedef named_parameter<char, struct no_params_type_t,char> no_params_type;
  211. namespace {
  212. no_params_type no_params( '\0' );
  213. } // local namespace
  214. // ************************************************************************** //
  215. // ************** keyword ************** //
  216. // ************************************************************************** //
  217. template<typename unique_id, bool required = false>
  218. struct keyword {
  219. typedef unique_id id;
  220. template<typename T>
  221. named_parameter<T const,unique_id>
  222. operator=( T const& t ) const { return named_parameter<T const,unique_id>( t ); }
  223. template<typename T>
  224. named_parameter<T,unique_id>
  225. operator=( T& t ) const { return named_parameter<T,unique_id>( t ); }
  226. named_parameter<char const*,unique_id,char const*>
  227. operator=( char const* t ) const { return named_parameter<char const*,unique_id,char const*>( t ); }
  228. };
  229. //____________________________________________________________________________//
  230. // ************************************************************************** //
  231. // ************** typed_keyword ************** //
  232. // ************************************************************************** //
  233. template<typename T, typename unique_id, bool required>
  234. struct typed_keyword : keyword<unique_id,required> {
  235. named_parameter<T const,unique_id>
  236. operator=( T const& t ) const { return named_parameter<T const,unique_id>( t ); }
  237. named_parameter<T,unique_id>
  238. operator=( T& t ) const { return named_parameter<T,unique_id>( t ); }
  239. };
  240. //____________________________________________________________________________//
  241. template<typename unique_id, bool required>
  242. struct typed_keyword<bool,unique_id,required>
  243. : keyword<unique_id,required>
  244. , named_parameter<bool,unique_id,bool> {
  245. typedef unique_id id;
  246. typed_keyword() : named_parameter<bool,unique_id,bool>( true ) {}
  247. named_parameter<bool,unique_id,bool>
  248. operator!() const { return named_parameter<bool,unique_id,bool>( false ); }
  249. };
  250. // ************************************************************************** //
  251. // ************** opt_assign ************** //
  252. // ************************************************************************** //
  253. template<typename T, typename Params, typename Keyword>
  254. inline typename enable_if_c<!has_param<Params,Keyword>::value,void>::type
  255. opt_assign( T& /*target*/, Params const& /*p*/, Keyword /*k*/ )
  256. {
  257. }
  258. //____________________________________________________________________________//
  259. template<typename T, typename Params, typename Keyword>
  260. inline typename enable_if_c<has_param<Params,Keyword>::value,void>::type
  261. opt_assign( T& target, Params const& p, Keyword k )
  262. {
  263. using namespace unit_test;
  264. assign_op( target, p[k], static_cast<int>(0) );
  265. }
  266. // ************************************************************************** //
  267. // ************** opt_get ************** //
  268. // ************************************************************************** //
  269. template<typename T, typename Params, typename Keyword>
  270. inline T
  271. opt_get( Params const& p, Keyword k, T default_val )
  272. {
  273. opt_assign( default_val, p, k );
  274. return default_val;
  275. }
  276. // ************************************************************************** //
  277. // ************** opt_get ************** //
  278. // ************************************************************************** //
  279. template<typename Params, typename NP>
  280. inline typename enable_if_c<!has_param<Params,keyword<typename NP::id> >::value,
  281. named_parameter_combine<NP,Params> >::type
  282. opt_append( Params const& params, NP const& np )
  283. {
  284. return (params,np);
  285. }
  286. //____________________________________________________________________________//
  287. template<typename Params, typename NP>
  288. inline typename enable_if_c<has_param<Params,keyword<typename NP::id> >::value,Params>::type
  289. opt_append( Params const& params, NP const& )
  290. {
  291. return params;
  292. }
  293. } // namespace nfp
  294. } // namespace boost
  295. #include <boost/test/detail/enable_warnings.hpp>
  296. #endif // BOOST_TEST_UTILS_NAMED_PARAM