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
43namespace boost {
44namespace nfp { // named function parameters
45
46// ************************************************************************** //
47// ************** forward declarations ************** //
48// ************************************************************************** //
49
50template<typename unique_id, bool required> struct keyword;
51template<typename T, typename unique_id, bool required = false> struct typed_keyword;
52
53template<typename T, typename unique_id, typename RefType=T&> struct named_parameter;
54template<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
62template<typename T>
63struct is_named_param_pack : public mpl::false_ {};
64
65template<typename T, typename unique_id, typename RefType>
66struct is_named_param_pack<named_parameter<T,unique_id,RefType> > : public mpl::true_ {};
67
68template<typename NP, typename Rest>
69struct 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 is the type of the parameter
76/// corresponding to the Keyword (if parameter is present) or Default
77
78template<typename NP, typename Keyword, typename DefaultType=void>
79struct 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
84template<typename NP, typename Rest, typename Keyword, typename DefaultType>
85struct 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 id Params has parameter corresponding
95/// to the Keyword
96
97template<typename NP, typename Keyword>
98struct has_param : is_same<typename NP::id,typename Keyword::id> {};
99
100template<typename NP, typename Rest, typename Keyword>
101struct 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
109namespace nfp_detail {
110
111struct access_to_invalid_parameter {};
112
113//____________________________________________________________________________//
114
115inline void
116report_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
127struct nil {
128 template<typename T>
129#if defined(__GNUC__) || defined(__HP_aCC) || defined(__EDG__) || defined(__SUNPRO_CC)
130 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>
137 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>
141 nil operator()( Arg1 const& )
142 { nfp_detail::report_access_to_invalid_parameter(true); return nil(); }
143
144 template<typename Arg1,typename Arg2>
145 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>
149 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>
154 void apply_to( Visitor& /*v*/ ) const {}
155
156 static nil& inst() { static nil s_inst; return s_inst; }
157private:
158 nil() {}
159};
160
161// ************************************************************************** //
162// ************** named_parameter_base ************** //
163// ************************************************************************** //
164
165namespace nfp_detail {
166
167template<typename Derived>
168struct named_parameter_base {
169 template<typename NP>
170 named_parameter_combine<NP,Derived>
171 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
180template<typename NP, typename Rest = nil>
181struct 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
188 named_parameter_combine( NP const& np, Rest const& r )
189 : Rest( r )
190 , m_param( np )
191 {
192 }
193
194 // Access methods
195 res_type operator[]( keyword<typename NP::id,true> kw ) const { return m_param[kw]; }
196 res_type operator[]( keyword<typename NP::id,false> kw ) const { return m_param[kw]; }
197 using Rest::operator[];
198
199 bool has( keyword<typename NP::id,false> kw ) const { return m_param.has( kw ); }
200 using Rest::has;
201
202 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>
209 void apply_to( Visitor& V ) const
210 {
211 m_param.apply_to( V );
212
213 Rest::apply_to( V );
214 }
215private:
216 // Data members
217 NP m_param;
218};
219
220// ************************************************************************** //
221// ************** named_parameter ************** //
222// ************************************************************************** //
223
224template<typename T, typename unique_id, typename RefType>
225struct 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
233 explicit named_parameter( ref_type v )
234 : m_value( v )
235 , m_erased( false )
236 {}
237 named_parameter( named_parameter const& np )
238 : m_value( np.m_value )
239 , m_erased( np.m_erased )
240 {}
241
242 // Access methods
243 ref_type operator[]( keyword<unique_id,true> ) const { return m_erased ? nil::inst().template any_cast<ref_type>() : m_value; }
244 ref_type operator[]( keyword<unique_id,false> ) const { return m_erased ? nil::inst().template any_cast<ref_type>() : m_value; }
245 template<typename UnknownId>
246 nil operator[]( keyword<UnknownId,false> ) const { return nil::inst(); }
247
248 bool has( keyword<unique_id,false> ) const { return !m_erased; }
249 template<typename UnknownId>
250 bool has( keyword<UnknownId,false> ) const { return false; }
251
252 void erase( keyword<unique_id,false> ) const { m_erased = true; }
253 template<typename UnknownId>
254 void erase( keyword<UnknownId,false> ) const {}
255
256 // Visitation support
257 template<typename Visitor>
258 void apply_to( Visitor& V ) const
259 {
260 V.set_parameter( rtti::type_id<unique_id>(), m_value );
261 }
262
263private:
264 // Data members
265 ref_type m_value;
266 mutable bool m_erased;
267};
268
269// ************************************************************************** //
270// ************** no_params ************** //
271// ************************************************************************** //
272
273typedef named_parameter<char, struct no_params_type_t,char> no_params_type;
274
275namespace {
276no_params_type no_params( '\0' );
277} // local namespace
278
279// ************************************************************************** //
280// ************** keyword ************** //
281// ************************************************************************** //
282
283template<typename unique_id, bool required = false>
284struct keyword {
285 typedef unique_id id;
286
287 template<typename T>
288 named_parameter<T const,unique_id>
289 operator=( T const& t ) const { return named_parameter<T const,unique_id>( t ); }
290
291 template<typename T>
292 named_parameter<T,unique_id>
293 operator=( T& t ) const { return named_parameter<T,unique_id>( t ); }
294
295 named_parameter<char const*,unique_id,char const*>
296 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
305template<typename T, typename unique_id, bool required>
306struct typed_keyword : keyword<unique_id,required> {
307 named_parameter<T const,unique_id>
308 operator=( T const& t ) const { return named_parameter<T const,unique_id>( t ); }
309
310 named_parameter<T,unique_id>
311 operator=( T& t ) const { return named_parameter<T,unique_id>( t ); }
312};
313
314//____________________________________________________________________________//
315
316template<typename unique_id, bool required>
317struct typed_keyword<bool,unique_id,required>
318: keyword<unique_id,required>
319, named_parameter<bool,unique_id,bool> {
320 typedef unique_id id;
321
322 typed_keyword() : named_parameter<bool,unique_id,bool>( true ) {}
323
324 named_parameter<bool,unique_id,bool>
325 operator!() const { return named_parameter<bool,unique_id,bool>( false ); }
326};
327
328// ************************************************************************** //
329// ************** opt_assign ************** //
330// ************************************************************************** //
331
332template<typename T, typename Params, typename Keyword>
333inline typename enable_if_c<!has_param<Params,Keyword>::value,void>::type
334opt_assign( T& target, Params const& p, Keyword k )
335{
336}
337
338//____________________________________________________________________________//
339
340template<typename T, typename Params, typename Keyword>
341inline typename enable_if_c<has_param<Params,Keyword>::value,void>::type
342opt_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
353template<typename T, typename Params, typename Keyword>
354inline T
355opt_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
366template<typename Params, typename NP>
367inline typename enable_if_c<!has_param<Params,keyword<typename NP::id> >::value,
368named_parameter_combine<NP,Params> >::type
369opt_append( Params const& params, NP const& np )
370{
371 return (params,np);
372}
373
374//____________________________________________________________________________//
375
376template<typename Params, typename NP>
377inline typename enable_if_c<has_param<Params,keyword<typename NP::id> >::value,Params>::type
378opt_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