//  (C) Copyright Gennadiy Rozental 2005-2007.

//  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: 43798 $

//

//  Description : facilities for named function parameters support

// ***************************************************************************



#ifndef BOOST_TEST_NAMED_PARAM_022505GER

#define BOOST_TEST_NAMED_PARAM_022505GER



// 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/test/detail/suppress_warnings.hpp>



//____________________________________________________________________________//



namespace boost {



namespace nfp { // named function parameters



// ************************************************************************** //

// **************              forward declarations            ************** //

// ************************************************************************** //



template<typename T, typename unique_id,typename RefType>   struct named_parameter;

template<typename unique_id,bool required>                  struct keyword;



namespace nfp_detail {



template<typename NP1,typename NP2>        struct named_parameter_combine;



// ************************************************************************** //

// **************          access_to_invalid_parameter         ************** //

// ************************************************************************** //



struct access_to_invalid_parameter {};



//____________________________________________________________________________//



inline void 

report_access_to_invalid_parameter()

{

    throw access_to_invalid_parameter();

}



//____________________________________________________________________________//



// ************************************************************************** //

// **************                       nil                    ************** //

// ************************************************************************** //



struct nil {

    template<typename T>

    operator T() const

    { report_access_to_invalid_parameter(); static T* v = 0; return *v; }



    template<typename Arg1>

    nil operator()( Arg1 const& )

    { report_access_to_invalid_parameter(); return nil(); }



    template<typename Arg1,typename Arg2>

    nil operator()( Arg1 const&, Arg2 const& )

    { report_access_to_invalid_parameter(); return nil(); }



    template<typename Arg1,typename Arg2,typename Arg3>

    nil operator()( Arg1 const&, Arg2 const&, Arg3 const& )

    { report_access_to_invalid_parameter(); return nil(); }



    // Visitation support

    template<typename Visitor>

    void            apply_to( Visitor& V ) const {}

};

    

// ************************************************************************** //

// **************              named_parameter_base            ************** //

// ************************************************************************** //



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) ); }

};



//____________________________________________________________________________//



// ************************************************************************** //

// **************             named_parameter_combine          ************** //

// ************************************************************************** //



template<typename NP, typename Rest = nil>

struct named_parameter_combine : Rest, 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> ) const             { return true; }

    using       Rest::has;



#if BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3206))

    template<typename NP>

    named_parameter_combine<NP,self_type> operator,( NP const& np ) const

    { return named_parameter_combine<NP,self_type>( np, *this ); }

#else

    using       named_parameter_base<named_parameter_combine<NP,Rest> >::operator,;

#endif



    // 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;

};



} // namespace nfp_detail



// ************************************************************************** //

// **************             named_parameter_combine          ************** //

// ************************************************************************** //



template<typename T, typename unique_id,typename ReferenceType=T&>

struct named_parameter

: nfp_detail::named_parameter_base<named_parameter<T, unique_id,ReferenceType> >

{

    typedef T               data_type;

    typedef ReferenceType   ref_type;

    typedef unique_id       id;



    // Constructor

    explicit        named_parameter( ref_type v ) : m_value( v ) {}



    // Access methods

    ref_type        operator[]( keyword<unique_id,true> ) const     { return m_value; }

    ref_type        operator[]( keyword<unique_id,false> ) const    { return m_value; }

    template<typename UnknownId>

    nfp_detail::nil  operator[]( keyword<UnknownId,false> ) const   { return nfp_detail::nil(); }



    bool            has( keyword<unique_id,false> ) const           { return true; }

    template<typename UnknownId>

    bool            has( keyword<UnknownId,false> ) const           { return false; }



    // 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;

};



//____________________________________________________________________________//



// ************************************************************************** //

// **************                    no_params                 ************** //

// ************************************************************************** //



namespace nfp_detail {

typedef named_parameter<char, struct no_params_type_t,char> no_params_type;

}



namespace {

nfp_detail::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 = false>

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>

struct typed_keyword<bool,unique_id,false>

: keyword<unique_id,false>

, 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 ); }

};



//____________________________________________________________________________//



// ************************************************************************** //

// **************                optionally_assign             ************** //

// ************************************************************************** //



template<typename T>

inline void

optionally_assign( T&, nfp_detail::nil )

{

    nfp_detail::report_access_to_invalid_parameter();

}



//____________________________________________________________________________//



template<typename T, typename Source>

inline void

#if BOOST_WORKAROUND( __MWERKS__, BOOST_TESTED_AT( 0x3003 ) ) \

    || BOOST_WORKAROUND( __DECCXX_VER, BOOST_TESTED_AT(60590042) )

optionally_assign( T& target, Source src )

#else

optionally_assign( T& target, Source const& src )

#endif

{

    using namespace unit_test;



    assign_op( target, src, 0 );

}



//____________________________________________________________________________//



template<typename T, typename Params, typename Keyword>

inline void

optionally_assign( T& target, Params const& p, Keyword k )

{

    if( p.has(k) )

        optionally_assign( target, p[k] );

}



//____________________________________________________________________________//



} // namespace nfp



} // namespace boost



#include <boost/test/detail/enable_warnings.hpp>



#endif // BOOST_TEST_NAMED_PARAM_022505GER



