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 
6 //  See http://www.boost.org/libs/test for the library home page.
7 //
8 //  File        : $RCSfile$
9 //
10 //  Version     : $Revision$
11 //
12 //  Description : named function parameters library
13 // ***************************************************************************
14 
15 #ifndef BOOST_TEST_UTILS_NAMED_PARAM
16 #define BOOST_TEST_UTILS_NAMED_PARAM
17 
18 // Boost
19 #include <boost/config.hpp>
20 #include <boost/detail/workaround.hpp>
21 
22 // Boost.Test
23 #include <boost/test/utils/rtti.hpp>
24 #include <boost/test/utils/assign_op.hpp>
25 
26 #include <boost/type_traits/remove_reference.hpp>
27 #include <boost/type_traits/remove_cv.hpp>
28 
29 #include <boost/test/detail/throw_exception.hpp>
30 
31 // Boost
32 #include <boost/mpl/if.hpp>
33 #include <boost/mpl/or.hpp>
34 #include <boost/type_traits/is_same.hpp>
35 #include <boost/type_traits/remove_cv.hpp>
36 #include <boost/utility/enable_if.hpp>
37 #include <boost/mpl/bool.hpp>
38 
39 #include <boost/test/detail/suppress_warnings.hpp>
40 
41 //____________________________________________________________________________//
42 
43 namespace boost {
44 namespace nfp { // named function parameters
45 
46 // ************************************************************************** //
47 // **************             forward declarations             ************** //
48 // ************************************************************************** //
49 
50 template<typename unique_id, bool required>                     struct keyword;
51 template<typename T, typename unique_id, bool required = false> struct typed_keyword;
52 
53 template<typename T, typename unique_id, typename RefType=T&>   struct named_parameter;
54 template<typename NP1,typename NP2>                             struct named_parameter_combine;
55 
56 // ************************************************************************** //
57 // **************              is_named_param_pack             ************** //
58 // ************************************************************************** //
59 
60 /// is_named_param_pack<T>::value is true if T is parameters pack
61 
62 template<typename T>
63 struct is_named_param_pack : public mpl::false_ {};
64 
65 template<typename T, typename unique_id, typename RefType>
66 struct is_named_param_pack<named_parameter<T,unique_id,RefType> > : public mpl::true_ {};
67 
68 template<typename NP, typename Rest>
69 struct is_named_param_pack<named_parameter_combine<NP,Rest> > : public mpl::true_ {};
70 
71 // ************************************************************************** //
72 // **************                  param_type                  ************** //
73 // ************************************************************************** //
74 
75 /// param_type<Params,Keyword,Default>::type is the type of the parameter
76 /// corresponding to the Keyword (if parameter is present) or Default
77 
78 template<typename NP, typename Keyword, typename DefaultType=void>
79 struct param_type
80 : mpl::if_<typename is_same<typename NP::id,typename Keyword::id>::type,
81            typename remove_cv<typename NP::data_type>::type,
82            DefaultType> {};
83 
84 template<typename NP, typename Rest, typename Keyword, typename DefaultType>
85 struct param_type<named_parameter_combine<NP,Rest>,Keyword,DefaultType>
86 : mpl::if_<typename is_same<typename NP::id,typename Keyword::id>::type,
87            typename remove_cv<typename NP::data_type>::type,
88            typename param_type<Rest,Keyword,DefaultType>::type> {};
89 
90 // ************************************************************************** //
91 // **************                  has_param                   ************** //
92 // ************************************************************************** //
93 
94 /// has_param<Params,Keyword>::value is true if Params has parameter corresponding
95 /// to the Keyword
96 
97 template<typename NP, typename Keyword>
98 struct has_param : is_same<typename NP::id,typename Keyword::id> {};
99 
100 template<typename NP, typename Rest, typename Keyword>
101 struct has_param<named_parameter_combine<NP,Rest>,Keyword>
102 : mpl::or_<typename is_same<typename NP::id,typename Keyword::id>::type,
103            typename has_param<Rest,Keyword>::type> {};
104 
105 // ************************************************************************** //
106 // **************          access_to_invalid_parameter         ************** //
107 // ************************************************************************** //
108 
109 namespace nfp_detail {
110 
111 struct access_to_invalid_parameter {};
112 
113 //____________________________________________________________________________//
114 
115 inline void
report_access_to_invalid_parameter(bool v)116 report_access_to_invalid_parameter( bool v )
117 {
118     BOOST_TEST_I_ASSRT( !v, access_to_invalid_parameter() );
119 }
120 
121 } // namespace nfp_detail
122 
123 // ************************************************************************** //
124 // **************                      nil                     ************** //
125 // ************************************************************************** //
126 
127 struct nil {
128     template<typename T>
129 #if defined(__GNUC__) || defined(__HP_aCC) || defined(__EDG__) || defined(__SUNPRO_CC) || defined(BOOST_EMBTC)
operator Tboost::nfp::nil130     operator T() const
131 #else
132     operator T const&() const
133 #endif
134     { nfp_detail::report_access_to_invalid_parameter(true); static T* v = 0; return *v; }
135 
136     template<typename T>
any_castboost::nfp::nil137     T any_cast() const
138     { nfp_detail::report_access_to_invalid_parameter(true); static typename remove_reference<T>::type* v = 0; return *v; }
139 
140     template<typename Arg1>
operator ()boost::nfp::nil141     nil operator()( Arg1 const& )
142     { nfp_detail::report_access_to_invalid_parameter(true); return nil(); }
143 
144     template<typename Arg1,typename Arg2>
operator ()boost::nfp::nil145     nil operator()( Arg1 const&, Arg2 const& )
146     { nfp_detail::report_access_to_invalid_parameter(true); return nil(); }
147 
148     template<typename Arg1,typename Arg2,typename Arg3>
operator ()boost::nfp::nil149     nil operator()( Arg1 const&, Arg2 const&, Arg3 const& )
150     { nfp_detail::report_access_to_invalid_parameter(true); return nil(); }
151 
152     // Visitation support
153     template<typename Visitor>
apply_toboost::nfp::nil154     void            apply_to( Visitor& /*v*/ ) const {}
155 
instboost::nfp::nil156     static nil&     inst() { static nil s_inst; return s_inst; }
157 private:
nilboost::nfp::nil158     nil() {}
159 };
160 
161 // ************************************************************************** //
162 // **************             named_parameter_base             ************** //
163 // ************************************************************************** //
164 
165 namespace nfp_detail {
166 
167 template<typename Derived>
168 struct named_parameter_base {
169     template<typename NP>
170     named_parameter_combine<NP,Derived>
operator ,boost::nfp::nfp_detail::named_parameter_base171     operator,( NP const& np ) const { return named_parameter_combine<NP,Derived>( np, *static_cast<Derived const*>(this) ); }
172 };
173 
174 } // namespace nfp_detail
175 
176 // ************************************************************************** //
177 // **************            named_parameter_combine           ************** //
178 // ************************************************************************** //
179 
180 template<typename NP, typename Rest = nil>
181 struct named_parameter_combine
182 : Rest
183 , nfp_detail::named_parameter_base<named_parameter_combine<NP,Rest> > {
184     typedef typename NP::ref_type  res_type;
185     typedef named_parameter_combine<NP,Rest> self_type;
186 
187     // Constructor
named_parameter_combineboost::nfp::named_parameter_combine188     named_parameter_combine( NP const& np, Rest const& r )
189     : Rest( r )
190     , m_param( np )
191     {
192     }
193 
194     // Access methods
operator []boost::nfp::named_parameter_combine195     res_type    operator[]( keyword<typename NP::id,true> kw ) const    { return m_param[kw]; }
operator []boost::nfp::named_parameter_combine196     res_type    operator[]( keyword<typename NP::id,false> kw ) const   { return m_param[kw]; }
197     using       Rest::operator[];
198 
hasboost::nfp::named_parameter_combine199     bool        has( keyword<typename NP::id,false> kw ) const          { return m_param.has( kw ); }
200     using       Rest::has;
201 
eraseboost::nfp::named_parameter_combine202     void        erase( keyword<typename NP::id,false> kw ) const        { m_param.erase( kw ); }
203     using       Rest::erase;
204 
205     using       nfp_detail::named_parameter_base<named_parameter_combine<NP,Rest> >::operator,;
206 
207     // Visitation support
208     template<typename Visitor>
apply_toboost::nfp::named_parameter_combine209     void            apply_to( Visitor& V ) const
210     {
211         m_param.apply_to( V );
212 
213         Rest::apply_to( V );
214     }
215 private:
216     // Data members
217     NP          m_param;
218 };
219 
220 // ************************************************************************** //
221 // **************                named_parameter               ************** //
222 // ************************************************************************** //
223 
224 template<typename T, typename unique_id, typename RefType>
225 struct named_parameter
226 : nfp_detail::named_parameter_base<named_parameter<T,unique_id,RefType> >
227 {
228     typedef T               data_type;
229     typedef RefType         ref_type;
230     typedef unique_id       id;
231 
232     // Constructor
named_parameterboost::nfp::named_parameter233     explicit        named_parameter( ref_type v )
234     : m_value( v )
235     , m_erased( false )
236     {}
named_parameterboost::nfp::named_parameter237     named_parameter( named_parameter const& np )
238     : m_value( np.m_value )
239     , m_erased( np.m_erased )
240     {}
241 
242     // Access methods
operator []boost::nfp::named_parameter243     ref_type        operator[]( keyword<unique_id,true> ) const     { return m_erased ? nil::inst().template any_cast<ref_type>() :  m_value; }
operator []boost::nfp::named_parameter244     ref_type        operator[]( keyword<unique_id,false> ) const    { return m_erased ? nil::inst().template any_cast<ref_type>() :  m_value; }
245     template<typename UnknownId>
operator []boost::nfp::named_parameter246     nil             operator[]( keyword<UnknownId,false> ) const    { return nil::inst(); }
247 
hasboost::nfp::named_parameter248     bool            has( keyword<unique_id,false> ) const           { return !m_erased; }
249     template<typename UnknownId>
hasboost::nfp::named_parameter250     bool            has( keyword<UnknownId,false> ) const           { return false; }
251 
eraseboost::nfp::named_parameter252     void            erase( keyword<unique_id,false> ) const         { m_erased = true; }
253     template<typename UnknownId>
eraseboost::nfp::named_parameter254     void            erase( keyword<UnknownId,false> ) const         {}
255 
256     // Visitation support
257     template<typename Visitor>
apply_toboost::nfp::named_parameter258     void            apply_to( Visitor& V ) const
259     {
260         V.set_parameter( rtti::type_id<unique_id>(), m_value );
261     }
262 
263 private:
264     // Data members
265     ref_type        m_value;
266     mutable bool    m_erased;
267 };
268 
269 // ************************************************************************** //
270 // **************                   no_params                  ************** //
271 // ************************************************************************** //
272 
273 typedef named_parameter<char, struct no_params_type_t,char> no_params_type;
274 
275 namespace {
276 no_params_type no_params( '\0' );
277 } // local namespace
278 
279 // ************************************************************************** //
280 // **************                    keyword                   ************** //
281 // ************************************************************************** //
282 
283 template<typename unique_id, bool required = false>
284 struct keyword {
285     typedef unique_id id;
286 
287     template<typename T>
288     named_parameter<T const,unique_id>
operator =boost::nfp::keyword289     operator=( T const& t ) const       { return named_parameter<T const,unique_id>( t ); }
290 
291     template<typename T>
292     named_parameter<T,unique_id>
operator =boost::nfp::keyword293     operator=( T& t ) const             { return named_parameter<T,unique_id>( t ); }
294 
295     named_parameter<char const*,unique_id,char const*>
operator =boost::nfp::keyword296     operator=( char const* t ) const    { return named_parameter<char const*,unique_id,char const*>( t ); }
297 };
298 
299 //____________________________________________________________________________//
300 
301 // ************************************************************************** //
302 // **************                 typed_keyword                ************** //
303 // ************************************************************************** //
304 
305 template<typename T, typename unique_id, bool required>
306 struct typed_keyword : keyword<unique_id,required> {
307     named_parameter<T const,unique_id>
operator =boost::nfp::typed_keyword308     operator=( T const& t ) const       { return named_parameter<T const,unique_id>( t ); }
309 
310     named_parameter<T,unique_id>
operator =boost::nfp::typed_keyword311     operator=( T& t ) const             { return named_parameter<T,unique_id>( t ); }
312 };
313 
314 //____________________________________________________________________________//
315 
316 template<typename unique_id, bool required>
317 struct typed_keyword<bool,unique_id,required>
318 : keyword<unique_id,required>
319 , named_parameter<bool,unique_id,bool> {
320     typedef unique_id id;
321 
typed_keywordboost::nfp::typed_keyword322     typed_keyword() : named_parameter<bool,unique_id,bool>( true ) {}
323 
324     named_parameter<bool,unique_id,bool>
operator !boost::nfp::typed_keyword325     operator!() const           { return named_parameter<bool,unique_id,bool>( false ); }
326 };
327 
328 // ************************************************************************** //
329 // **************                  opt_assign                  ************** //
330 // ************************************************************************** //
331 
332 template<typename T, typename Params, typename Keyword>
333 inline typename enable_if_c<!has_param<Params,Keyword>::value,void>::type
opt_assign(T &,Params const &,Keyword)334 opt_assign( T& /*target*/, Params const& /*p*/, Keyword /*k*/ )
335 {
336 }
337 
338 //____________________________________________________________________________//
339 
340 template<typename T, typename Params, typename Keyword>
341 inline typename enable_if_c<has_param<Params,Keyword>::value,void>::type
opt_assign(T & target,Params const & p,Keyword k)342 opt_assign( T& target, Params const& p, Keyword k )
343 {
344     using namespace unit_test;
345 
346     assign_op( target, p[k], static_cast<int>(0) );
347 }
348 
349 // ************************************************************************** //
350 // **************                    opt_get                   ************** //
351 // ************************************************************************** //
352 
353 template<typename T, typename Params, typename Keyword>
354 inline T
opt_get(Params const & p,Keyword k,T default_val)355 opt_get( Params const& p, Keyword k, T default_val )
356 {
357     opt_assign( default_val, p, k );
358 
359     return default_val;
360 }
361 
362 // ************************************************************************** //
363 // **************                    opt_get                   ************** //
364 // ************************************************************************** //
365 
366 template<typename Params, typename NP>
367 inline typename enable_if_c<!has_param<Params,keyword<typename NP::id> >::value,
368 named_parameter_combine<NP,Params> >::type
opt_append(Params const & params,NP const & np)369 opt_append( Params const& params, NP const& np )
370 {
371     return (params,np);
372 }
373 
374 //____________________________________________________________________________//
375 
376 template<typename Params, typename NP>
377 inline typename enable_if_c<has_param<Params,keyword<typename NP::id> >::value,Params>::type
opt_append(Params const & params,NP const &)378 opt_append( Params const& params, NP const& )
379 {
380     return params;
381 }
382 
383 } // namespace nfp
384 } // namespace boost
385 
386 #include <boost/test/detail/enable_warnings.hpp>
387 
388 #endif // BOOST_TEST_UTILS_NAMED_PARAM
389