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