389 lines
15 KiB
C++
389 lines
15 KiB
C++
// (C) Copyright Gennadiy Rozental 2001.
|
|
// Distributed under the Boost Software License, Version 1.0.
|
|
// (See accompanying file LICENSE_1_0.txt or copy at
|
|
// http://www.boost.org/LICENSE_1_0.txt)
|
|
|
|
// See http://www.boost.org/libs/test for the library home page.
|
|
//
|
|
// File : $RCSfile$
|
|
//
|
|
// Version : $Revision$
|
|
//
|
|
// Description : named function parameters library
|
|
// ***************************************************************************
|
|
|
|
#ifndef BOOST_TEST_UTILS_NAMED_PARAM
|
|
#define BOOST_TEST_UTILS_NAMED_PARAM
|
|
|
|
// Boost
|
|
#include <boost/config.hpp>
|
|
#include <boost/detail/workaround.hpp>
|
|
|
|
// Boost.Test
|
|
#include <boost/test/utils/rtti.hpp>
|
|
#include <boost/test/utils/assign_op.hpp>
|
|
|
|
#include <boost/type_traits/remove_reference.hpp>
|
|
#include <boost/type_traits/remove_cv.hpp>
|
|
|
|
#include <boost/test/detail/throw_exception.hpp>
|
|
|
|
// Boost
|
|
#include <boost/mpl/if.hpp>
|
|
#include <boost/mpl/or.hpp>
|
|
#include <boost/type_traits/is_same.hpp>
|
|
#include <boost/type_traits/remove_cv.hpp>
|
|
#include <boost/utility/enable_if.hpp>
|
|
#include <boost/mpl/bool.hpp>
|
|
|
|
#include <boost/test/detail/suppress_warnings.hpp>
|
|
|
|
//____________________________________________________________________________//
|
|
|
|
namespace boost {
|
|
namespace nfp { // named function parameters
|
|
|
|
// ************************************************************************** //
|
|
// ************** forward declarations ************** //
|
|
// ************************************************************************** //
|
|
|
|
template<typename unique_id, bool required> struct keyword;
|
|
template<typename T, typename unique_id, bool required = false> struct typed_keyword;
|
|
|
|
template<typename T, typename unique_id, typename RefType=T&> struct named_parameter;
|
|
template<typename NP1,typename NP2> struct named_parameter_combine;
|
|
|
|
// ************************************************************************** //
|
|
// ************** is_named_param_pack ************** //
|
|
// ************************************************************************** //
|
|
|
|
/// is_named_param_pack<T>::value is true if T is parameters pack
|
|
|
|
template<typename T>
|
|
struct is_named_param_pack : public mpl::false_ {};
|
|
|
|
template<typename T, typename unique_id, typename RefType>
|
|
struct is_named_param_pack<named_parameter<T,unique_id,RefType> > : public mpl::true_ {};
|
|
|
|
template<typename NP, typename Rest>
|
|
struct is_named_param_pack<named_parameter_combine<NP,Rest> > : public mpl::true_ {};
|
|
|
|
// ************************************************************************** //
|
|
// ************** param_type ************** //
|
|
// ************************************************************************** //
|
|
|
|
/// param_type<Params,Keyword,Default>::type is is the type of the parameter
|
|
/// corresponding to the Keyword (if parameter is present) or Default
|
|
|
|
template<typename NP, typename Keyword, typename DefaultType=void>
|
|
struct param_type
|
|
: mpl::if_<typename is_same<typename NP::id,typename Keyword::id>::type,
|
|
typename remove_cv<typename NP::data_type>::type,
|
|
DefaultType> {};
|
|
|
|
template<typename NP, typename Rest, typename Keyword, typename DefaultType>
|
|
struct param_type<named_parameter_combine<NP,Rest>,Keyword,DefaultType>
|
|
: mpl::if_<typename is_same<typename NP::id,typename Keyword::id>::type,
|
|
typename remove_cv<typename NP::data_type>::type,
|
|
typename param_type<Rest,Keyword,DefaultType>::type> {};
|
|
|
|
// ************************************************************************** //
|
|
// ************** has_param ************** //
|
|
// ************************************************************************** //
|
|
|
|
/// has_param<Params,Keyword>::value is true id Params has parameter corresponding
|
|
/// to the Keyword
|
|
|
|
template<typename NP, typename Keyword>
|
|
struct has_param : is_same<typename NP::id,typename Keyword::id> {};
|
|
|
|
template<typename NP, typename Rest, typename Keyword>
|
|
struct has_param<named_parameter_combine<NP,Rest>,Keyword>
|
|
: mpl::or_<typename is_same<typename NP::id,typename Keyword::id>::type,
|
|
typename has_param<Rest,Keyword>::type> {};
|
|
|
|
// ************************************************************************** //
|
|
// ************** access_to_invalid_parameter ************** //
|
|
// ************************************************************************** //
|
|
|
|
namespace nfp_detail {
|
|
|
|
struct access_to_invalid_parameter {};
|
|
|
|
//____________________________________________________________________________//
|
|
|
|
inline void
|
|
report_access_to_invalid_parameter( bool v )
|
|
{
|
|
BOOST_TEST_I_ASSRT( !v, access_to_invalid_parameter() );
|
|
}
|
|
|
|
} // namespace nfp_detail
|
|
|
|
// ************************************************************************** //
|
|
// ************** nil ************** //
|
|
// ************************************************************************** //
|
|
|
|
struct nil {
|
|
template<typename T>
|
|
#if defined(__GNUC__) || defined(__HP_aCC) || defined(__EDG__) || defined(__SUNPRO_CC)
|
|
operator T() const
|
|
#else
|
|
operator T const&() const
|
|
#endif
|
|
{ nfp_detail::report_access_to_invalid_parameter(true); static T* v = 0; return *v; }
|
|
|
|
template<typename T>
|
|
T any_cast() const
|
|
{ nfp_detail::report_access_to_invalid_parameter(true); static typename remove_reference<T>::type* v = 0; return *v; }
|
|
|
|
template<typename Arg1>
|
|
nil operator()( Arg1 const& )
|
|
{ nfp_detail::report_access_to_invalid_parameter(true); return nil(); }
|
|
|
|
template<typename Arg1,typename Arg2>
|
|
nil operator()( Arg1 const&, Arg2 const& )
|
|
{ nfp_detail::report_access_to_invalid_parameter(true); return nil(); }
|
|
|
|
template<typename Arg1,typename Arg2,typename Arg3>
|
|
nil operator()( Arg1 const&, Arg2 const&, Arg3 const& )
|
|
{ nfp_detail::report_access_to_invalid_parameter(true); return nil(); }
|
|
|
|
// Visitation support
|
|
template<typename Visitor>
|
|
void apply_to( Visitor& /*v*/ ) const {}
|
|
|
|
static nil& inst() { static nil s_inst; return s_inst; }
|
|
private:
|
|
nil() {}
|
|
};
|
|
|
|
// ************************************************************************** //
|
|
// ************** named_parameter_base ************** //
|
|
// ************************************************************************** //
|
|
|
|
namespace nfp_detail {
|
|
|
|
template<typename Derived>
|
|
struct named_parameter_base {
|
|
template<typename NP>
|
|
named_parameter_combine<NP,Derived>
|
|
operator,( NP const& np ) const { return named_parameter_combine<NP,Derived>( np, *static_cast<Derived const*>(this) ); }
|
|
};
|
|
|
|
} // namespace nfp_detail
|
|
|
|
// ************************************************************************** //
|
|
// ************** named_parameter_combine ************** //
|
|
// ************************************************************************** //
|
|
|
|
template<typename NP, typename Rest = nil>
|
|
struct named_parameter_combine
|
|
: Rest
|
|
, nfp_detail::named_parameter_base<named_parameter_combine<NP,Rest> > {
|
|
typedef typename NP::ref_type res_type;
|
|
typedef named_parameter_combine<NP,Rest> self_type;
|
|
|
|
// Constructor
|
|
named_parameter_combine( NP const& np, Rest const& r )
|
|
: Rest( r )
|
|
, m_param( np )
|
|
{
|
|
}
|
|
|
|
// Access methods
|
|
res_type operator[]( keyword<typename NP::id,true> kw ) const { return m_param[kw]; }
|
|
res_type operator[]( keyword<typename NP::id,false> kw ) const { return m_param[kw]; }
|
|
using Rest::operator[];
|
|
|
|
bool has( keyword<typename NP::id,false> kw ) const { return m_param.has( kw ); }
|
|
using Rest::has;
|
|
|
|
void erase( keyword<typename NP::id,false> kw ) const { m_param.erase( kw ); }
|
|
using Rest::erase;
|
|
|
|
using nfp_detail::named_parameter_base<named_parameter_combine<NP,Rest> >::operator,;
|
|
|
|
// Visitation support
|
|
template<typename Visitor>
|
|
void apply_to( Visitor& V ) const
|
|
{
|
|
m_param.apply_to( V );
|
|
|
|
Rest::apply_to( V );
|
|
}
|
|
private:
|
|
// Data members
|
|
NP m_param;
|
|
};
|
|
|
|
// ************************************************************************** //
|
|
// ************** named_parameter ************** //
|
|
// ************************************************************************** //
|
|
|
|
template<typename T, typename unique_id, typename RefType>
|
|
struct named_parameter
|
|
: nfp_detail::named_parameter_base<named_parameter<T,unique_id,RefType> >
|
|
{
|
|
typedef T data_type;
|
|
typedef RefType ref_type;
|
|
typedef unique_id id;
|
|
|
|
// Constructor
|
|
explicit named_parameter( ref_type v )
|
|
: m_value( v )
|
|
, m_erased( false )
|
|
{}
|
|
named_parameter( named_parameter const& np )
|
|
: m_value( np.m_value )
|
|
, m_erased( np.m_erased )
|
|
{}
|
|
|
|
// Access methods
|
|
ref_type operator[]( keyword<unique_id,true> ) const { return m_erased ? nil::inst().template any_cast<ref_type>() : m_value; }
|
|
ref_type operator[]( keyword<unique_id,false> ) const { return m_erased ? nil::inst().template any_cast<ref_type>() : m_value; }
|
|
template<typename UnknownId>
|
|
nil operator[]( keyword<UnknownId,false> ) const { return nil::inst(); }
|
|
|
|
bool has( keyword<unique_id,false> ) const { return !m_erased; }
|
|
template<typename UnknownId>
|
|
bool has( keyword<UnknownId,false> ) const { return false; }
|
|
|
|
void erase( keyword<unique_id,false> ) const { m_erased = true; }
|
|
template<typename UnknownId>
|
|
void erase( keyword<UnknownId,false> ) const {}
|
|
|
|
// Visitation support
|
|
template<typename Visitor>
|
|
void apply_to( Visitor& V ) const
|
|
{
|
|
V.set_parameter( rtti::type_id<unique_id>(), m_value );
|
|
}
|
|
|
|
private:
|
|
// Data members
|
|
ref_type m_value;
|
|
mutable bool m_erased;
|
|
};
|
|
|
|
// ************************************************************************** //
|
|
// ************** no_params ************** //
|
|
// ************************************************************************** //
|
|
|
|
typedef named_parameter<char, struct no_params_type_t,char> no_params_type;
|
|
|
|
namespace {
|
|
no_params_type no_params( '\0' );
|
|
} // local namespace
|
|
|
|
// ************************************************************************** //
|
|
// ************** keyword ************** //
|
|
// ************************************************************************** //
|
|
|
|
template<typename unique_id, bool required = false>
|
|
struct keyword {
|
|
typedef unique_id id;
|
|
|
|
template<typename T>
|
|
named_parameter<T const,unique_id>
|
|
operator=( T const& t ) const { return named_parameter<T const,unique_id>( t ); }
|
|
|
|
template<typename T>
|
|
named_parameter<T,unique_id>
|
|
operator=( T& t ) const { return named_parameter<T,unique_id>( t ); }
|
|
|
|
named_parameter<char const*,unique_id,char const*>
|
|
operator=( char const* t ) const { return named_parameter<char const*,unique_id,char const*>( t ); }
|
|
};
|
|
|
|
//____________________________________________________________________________//
|
|
|
|
// ************************************************************************** //
|
|
// ************** typed_keyword ************** //
|
|
// ************************************************************************** //
|
|
|
|
template<typename T, typename unique_id, bool required>
|
|
struct typed_keyword : keyword<unique_id,required> {
|
|
named_parameter<T const,unique_id>
|
|
operator=( T const& t ) const { return named_parameter<T const,unique_id>( t ); }
|
|
|
|
named_parameter<T,unique_id>
|
|
operator=( T& t ) const { return named_parameter<T,unique_id>( t ); }
|
|
};
|
|
|
|
//____________________________________________________________________________//
|
|
|
|
template<typename unique_id, bool required>
|
|
struct typed_keyword<bool,unique_id,required>
|
|
: keyword<unique_id,required>
|
|
, named_parameter<bool,unique_id,bool> {
|
|
typedef unique_id id;
|
|
|
|
typed_keyword() : named_parameter<bool,unique_id,bool>( true ) {}
|
|
|
|
named_parameter<bool,unique_id,bool>
|
|
operator!() const { return named_parameter<bool,unique_id,bool>( false ); }
|
|
};
|
|
|
|
// ************************************************************************** //
|
|
// ************** opt_assign ************** //
|
|
// ************************************************************************** //
|
|
|
|
template<typename T, typename Params, typename Keyword>
|
|
inline typename enable_if_c<!has_param<Params,Keyword>::value,void>::type
|
|
opt_assign( T& /*target*/, Params const& /*p*/, Keyword /*k*/ )
|
|
{
|
|
}
|
|
|
|
//____________________________________________________________________________//
|
|
|
|
template<typename T, typename Params, typename Keyword>
|
|
inline typename enable_if_c<has_param<Params,Keyword>::value,void>::type
|
|
opt_assign( T& target, Params const& p, Keyword k )
|
|
{
|
|
using namespace unit_test;
|
|
|
|
assign_op( target, p[k], static_cast<int>(0) );
|
|
}
|
|
|
|
// ************************************************************************** //
|
|
// ************** opt_get ************** //
|
|
// ************************************************************************** //
|
|
|
|
template<typename T, typename Params, typename Keyword>
|
|
inline T
|
|
opt_get( Params const& p, Keyword k, T default_val )
|
|
{
|
|
opt_assign( default_val, p, k );
|
|
|
|
return default_val;
|
|
}
|
|
|
|
// ************************************************************************** //
|
|
// ************** opt_get ************** //
|
|
// ************************************************************************** //
|
|
|
|
template<typename Params, typename NP>
|
|
inline typename enable_if_c<!has_param<Params,keyword<typename NP::id> >::value,
|
|
named_parameter_combine<NP,Params> >::type
|
|
opt_append( Params const& params, NP const& np )
|
|
{
|
|
return (params,np);
|
|
}
|
|
|
|
//____________________________________________________________________________//
|
|
|
|
template<typename Params, typename NP>
|
|
inline typename enable_if_c<has_param<Params,keyword<typename NP::id> >::value,Params>::type
|
|
opt_append( Params const& params, NP const& )
|
|
{
|
|
return params;
|
|
}
|
|
|
|
} // namespace nfp
|
|
} // namespace boost
|
|
|
|
#include <boost/test/detail/enable_warnings.hpp>
|
|
|
|
#endif // BOOST_TEST_UTILS_NAMED_PARAM
|