1 //  (C) Copyright Gennadiy Rozental 2005-2014.
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 : facilities for named function parameters support
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 #include <boost/mpl/bool.hpp>
22 
23 // Boost.Test
24 #include <boost/test/utils/rtti.hpp>
25 #include <boost/test/utils/assign_op.hpp>
26 
27 #include <boost/type_traits/remove_reference.hpp>
28 #include <boost/type_traits/remove_cv.hpp>
29 
30 #include <boost/test/detail/throw_exception.hpp>
31 
32 #include <boost/test/detail/suppress_warnings.hpp>
33 
34 //____________________________________________________________________________//
35 
36 namespace boost {
37 namespace nfp { // named function parameters
38 
39 // ************************************************************************** //
40 // **************             forward declarations             ************** //
41 // ************************************************************************** //
42 
43 template<typename T, typename unique_id,typename RefType>   struct named_parameter;
44 template<typename unique_id,bool required>                  struct keyword;
45 
46 namespace nfp_detail {
47 
48 template<typename NP1,typename NP2>        struct named_parameter_combine;
49 
50 // ************************************************************************** //
51 // **************          access_to_invalid_parameter         ************** //
52 // ************************************************************************** //
53 
54 struct access_to_invalid_parameter {};
55 
56 //____________________________________________________________________________//
57 
58 inline void
report_access_to_invalid_parameter(bool v)59 report_access_to_invalid_parameter(bool v)
60 {
61     if(v)
62         BOOST_TEST_IMPL_THROW( access_to_invalid_parameter() );
63 }
64 
65 //____________________________________________________________________________//
66 
67 // ************************************************************************** //
68 // **************                      nil                     ************** //
69 // ************************************************************************** //
70 
71 struct nil {
72     template<typename T>
73 #if defined(__GNUC__) || defined(__HP_aCC) || defined(__EDG__) || defined(__SUNPRO_CC)
operator Tboost::nfp::nfp_detail::nil74     operator T() const
75 #else
76     operator T const&() const
77 #endif
78     { report_access_to_invalid_parameter(true); static T* v = 0; return *v; }
79 
80     template<typename T>
any_castboost::nfp::nfp_detail::nil81     T any_cast() const
82     { report_access_to_invalid_parameter(true); static typename remove_reference<T>::type* v = 0; return *v; }
83 
84     template<typename Arg1>
operator ()boost::nfp::nfp_detail::nil85     nil operator()( Arg1 const& )
86     { report_access_to_invalid_parameter(true); return nil(); }
87 
88     template<typename Arg1,typename Arg2>
operator ()boost::nfp::nfp_detail::nil89     nil operator()( Arg1 const&, Arg2 const& )
90     { report_access_to_invalid_parameter(true); return nil(); }
91 
92     template<typename Arg1,typename Arg2,typename Arg3>
operator ()boost::nfp::nfp_detail::nil93     nil operator()( Arg1 const&, Arg2 const&, Arg3 const& )
94     { report_access_to_invalid_parameter(true); return nil(); }
95 
96     // Visitation support
97     template<typename Visitor>
apply_toboost::nfp::nfp_detail::nil98     void            apply_to( Visitor& /*v*/ ) const {}
99 
instboost::nfp::nfp_detail::nil100     static nil&     inst() { static nil s_inst; return s_inst; }
101 private:
nilboost::nfp::nfp_detail::nil102     nil() {}
103 };
104 
105 // ************************************************************************** //
106 // **************             named_parameter_base             ************** //
107 // ************************************************************************** //
108 
109 template<typename Derived>
110 struct named_parameter_base {
111     template<typename NP>
112     named_parameter_combine<NP,Derived>
operator ,boost::nfp::nfp_detail::named_parameter_base113     operator,( NP const& np ) const { return named_parameter_combine<NP,Derived>( np, *static_cast<Derived const*>(this) ); }
114 };
115 
116 //____________________________________________________________________________//
117 
118 // ************************************************************************** //
119 // **************            named_parameter_combine           ************** //
120 // ************************************************************************** //
121 
122 template<typename NP, typename Rest = nil>
123 struct named_parameter_combine
124 : Rest
125 , named_parameter_base<named_parameter_combine<NP,Rest> > {
126     typedef typename NP::ref_type  res_type;
127     typedef named_parameter_combine<NP,Rest> self_type;
128 
129     // Constructor
named_parameter_combineboost::nfp::nfp_detail::named_parameter_combine130     named_parameter_combine( NP const& np, Rest const& r )
131     : Rest( r )
132     , m_param( np )
133     {}
134 
135     // Access methods
operator []boost::nfp::nfp_detail::named_parameter_combine136     res_type    operator[]( keyword<typename NP::id,true> kw ) const    { return m_param[kw]; }
operator []boost::nfp::nfp_detail::named_parameter_combine137     res_type    operator[]( keyword<typename NP::id,false> kw ) const   { return m_param[kw]; }
138     using       Rest::operator[];
139 
hasboost::nfp::nfp_detail::named_parameter_combine140     bool        has( keyword<typename NP::id,false> kw ) const          { return m_param.has( kw ); }
141     using       Rest::has;
142 
eraseboost::nfp::nfp_detail::named_parameter_combine143     void        erase( keyword<typename NP::id,false> kw ) const        { m_param.erase( kw ); }
144     using       Rest::erase;
145 
146 #if BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3206)) || \
147     BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x0610))
148     template<typename NP>
operator ,boost::nfp::nfp_detail::named_parameter_combine149     named_parameter_combine<NP,self_type> operator,( NP const& np ) const
150     { return named_parameter_combine<NP,self_type>( np, *this ); }
151 #else
152     using       named_parameter_base<named_parameter_combine<NP,Rest> >::operator,;
153 #endif
154 
155     // Visitation support
156     template<typename Visitor>
apply_toboost::nfp::nfp_detail::named_parameter_combine157     void            apply_to( Visitor& V ) const
158     {
159         m_param.apply_to( V );
160 
161         Rest::apply_to( V );
162     }
163 private:
164     // Data members
165     NP          m_param;
166 };
167 
168 } // namespace nfp_detail
169 
170 // ************************************************************************** //
171 // **************                named_parameter               ************** //
172 // ************************************************************************** //
173 
174 template<typename T, typename unique_id, typename ReferenceType=T&>
175 struct named_parameter
176 : nfp_detail::named_parameter_base<named_parameter<T, unique_id,ReferenceType> >
177 {
178     typedef nfp_detail::nil nil_t;
179     typedef T               data_type;
180     typedef ReferenceType   ref_type;
181     typedef unique_id       id;
182 
183     // Constructor
named_parameterboost::nfp::named_parameter184     explicit        named_parameter( ref_type v )
185     : m_value( v )
186     , m_erased( false )
187     {}
named_parameterboost::nfp::named_parameter188     named_parameter( named_parameter const& np )
189     : m_value( np.m_value )
190     , m_erased( np.m_erased )
191     {}
192 
193     // Access methods
operator []boost::nfp::named_parameter194     ref_type        operator[]( keyword<unique_id,true> ) const     { return m_erased ? nil_t::inst().template any_cast<ref_type>() :  m_value; }
operator []boost::nfp::named_parameter195     ref_type        operator[]( keyword<unique_id,false> ) const    { return m_erased ? nil_t::inst().template any_cast<ref_type>() :  m_value; }
196     template<typename UnknownId>
operator []boost::nfp::named_parameter197     nil_t           operator[]( keyword<UnknownId,false> ) const    { return nil_t::inst(); }
198 
hasboost::nfp::named_parameter199     bool            has( keyword<unique_id,false> ) const           { return !m_erased; }
200     template<typename UnknownId>
hasboost::nfp::named_parameter201     bool            has( keyword<UnknownId,false> ) const           { return false; }
202 
eraseboost::nfp::named_parameter203     void            erase( keyword<unique_id,false> ) const         { m_erased = true; }
204     template<typename UnknownId>
eraseboost::nfp::named_parameter205     void            erase( keyword<UnknownId,false> ) const         {}
206 
207     // Visitation support
208     template<typename Visitor>
apply_toboost::nfp::named_parameter209     void            apply_to( Visitor& V ) const
210     {
211         V.set_parameter( rtti::type_id<unique_id>(), m_value );
212     }
213 
214 private:
215     // Data members
216     ref_type        m_value;
217     mutable bool    m_erased;
218 };
219 
220 //____________________________________________________________________________//
221 
222 // ************************************************************************** //
223 // **************                   no_params                  ************** //
224 // ************************************************************************** //
225 
226 namespace nfp_detail {
227 typedef named_parameter<char, struct no_params_type_t,char> no_params_type;
228 } // namespace nfp_detail
229 
230 namespace {
231 nfp_detail::no_params_type no_params( '\0' );
232 } // local namespace
233 
234 //____________________________________________________________________________//
235 
236 // ************************************************************************** //
237 // **************                    keyword                   ************** //
238 // ************************************************************************** //
239 
240 template<typename unique_id, bool required = false>
241 struct keyword {
242     typedef unique_id id;
243 
244     template<typename T>
245     named_parameter<T const,unique_id>
operator =boost::nfp::keyword246     operator=( T const& t ) const       { return named_parameter<T const,unique_id>( t ); }
247 
248     template<typename T>
249     named_parameter<T,unique_id>
operator =boost::nfp::keyword250     operator=( T& t ) const   { return named_parameter<T,unique_id>( t ); }
251 
252     named_parameter<char const*,unique_id,char const*>
operator =boost::nfp::keyword253     operator=( char const* t ) const   { return named_parameter<char const*,unique_id,char const*>( t ); }
254 };
255 
256 //____________________________________________________________________________//
257 
258 // ************************************************************************** //
259 // **************                 typed_keyword                ************** //
260 // ************************************************************************** //
261 
262 template<typename T, typename unique_id, bool required = false>
263 struct typed_keyword : keyword<unique_id,required> {
264     named_parameter<T const,unique_id>
operator =boost::nfp::typed_keyword265     operator=( T const& t ) const       { return named_parameter<T const,unique_id>( t ); }
266 
267     named_parameter<T,unique_id>
operator =boost::nfp::typed_keyword268     operator=( T& t ) const             { return named_parameter<T,unique_id>( t ); }
269 };
270 
271 //____________________________________________________________________________//
272 
273 template<typename unique_id>
274 struct typed_keyword<bool,unique_id,false>
275 : keyword<unique_id,false>
276 , named_parameter<bool,unique_id,bool> {
277     typedef unique_id id;
278 
typed_keywordboost::nfp::typed_keyword279     typed_keyword() : named_parameter<bool,unique_id,bool>( true ) {}
280 
281     named_parameter<bool,unique_id,bool>
operator !boost::nfp::typed_keyword282     operator!() const           { return named_parameter<bool,unique_id,bool>( false ); }
283 };
284 
285 //____________________________________________________________________________//
286 
287 // ************************************************************************** //
288 // **************               optionally_assign              ************** //
289 // ************************************************************************** //
290 
291 template<typename T>
292 inline void
optionally_assign(T &,nfp_detail::nil)293 optionally_assign( T&, nfp_detail::nil )
294 {
295     nfp_detail::report_access_to_invalid_parameter(true);
296 }
297 
298 //____________________________________________________________________________//
299 
300 template<typename T, typename Source>
301 inline void
302 #if BOOST_WORKAROUND( __MWERKS__, BOOST_TESTED_AT( 0x3003 ) ) \
303     || BOOST_WORKAROUND( __DECCXX_VER, BOOST_TESTED_AT(60590042) )
optionally_assign(T & target,Source src)304 optionally_assign( T& target, Source src )
305 #else
306 optionally_assign( T& target, Source const& src )
307 #endif
308 {
309     using namespace unit_test;
310 
311     assign_op( target, src, static_cast<int>(0) );
312 }
313 
314 //____________________________________________________________________________//
315 
316 template<typename T, typename Params, typename Keyword>
317 inline void
optionally_assign(T & target,Params const & p,Keyword k)318 optionally_assign( T& target, Params const& p, Keyword k )
319 {
320     if( p.has(k) )
321         optionally_assign( target, p[k] );
322 }
323 
324 //____________________________________________________________________________//
325 
326 // ************************************************************************** //
327 // **************                is_named_params               ************** //
328 // ************************************************************************** //
329 
330 template<typename T>
331 struct is_named_params : public boost::mpl::false_ {};
332 
333 template<typename T, typename unique_id, typename ReferenceType>
334 struct is_named_params<named_parameter<T,unique_id,ReferenceType> > : public boost::mpl::true_ {};
335 
336 template<typename NP, typename Rest>
337 struct is_named_params<nfp_detail::named_parameter_combine<NP,Rest> > : public boost::mpl::true_ {};
338 
339 // ************************************************************************** //
340 // **************                  param_type                  ************** //
341 // ************************************************************************** //
342 
343 template<typename Params,typename KeywordType,typename DefaultType=void>
344 struct param_type {
345     typedef DefaultType type;
346 };
347 
348 template<typename NP,typename Rest,typename Keyword,typename DefaultType>
349 struct param_type<nfp_detail::named_parameter_combine<NP,Rest>,Keyword,DefaultType> : param_type<Rest,Keyword,DefaultType> {
350 };
351 
352 template<typename T, typename unique_id, typename ReferenceType,bool required,typename DefaultType>
353 struct param_type<named_parameter<T,unique_id,ReferenceType>,keyword<unique_id,required>,DefaultType> {
354     typedef typename boost::remove_cv<T>::type type;
355 };
356 
357 template<typename T, typename unique_id, typename ReferenceType,typename Rest,bool required,typename DefaultType>
358 struct param_type<nfp_detail::named_parameter_combine<named_parameter<T,unique_id,ReferenceType>,Rest>,
359                   keyword<unique_id,required>,
360                   DefaultType> {
361     typedef typename boost::remove_cv<T>::type type;
362 };
363 
364 } // namespace nfp
365 } // namespace boost
366 
367 #include <boost/test/detail/enable_warnings.hpp>
368 
369 #endif // BOOST_TEST_UTILS_NAMED_PARAM
370 
371