Home | History | Annotate | Download | only in utils
      1 //  (C) Copyright Gennadiy Rozental 2005-2008.
      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: 54633 $
     11 //
     12 //  Description : facilities for named function parameters support
     13 // ***************************************************************************
     14 
     15 #ifndef BOOST_TEST_NAMED_PARAM_022505GER
     16 #define BOOST_TEST_NAMED_PARAM_022505GER
     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 
     28 #include <boost/test/detail/suppress_warnings.hpp>
     29 
     30 //____________________________________________________________________________//
     31 
     32 namespace boost {
     33 
     34 namespace nfp { // named function parameters
     35 
     36 // ************************************************************************** //
     37 // **************              forward declarations            ************** //
     38 // ************************************************************************** //
     39 
     40 template<typename T, typename unique_id,typename RefType>   struct named_parameter;
     41 template<typename unique_id,bool required>                  struct keyword;
     42 
     43 namespace nfp_detail {
     44 
     45 template<typename NP1,typename NP2>        struct named_parameter_combine;
     46 
     47 // ************************************************************************** //
     48 // **************          access_to_invalid_parameter         ************** //
     49 // ************************************************************************** //
     50 
     51 struct access_to_invalid_parameter {};
     52 
     53 //____________________________________________________________________________//
     54 
     55 inline void
     56 report_access_to_invalid_parameter()
     57 {
     58     throw access_to_invalid_parameter();
     59 }
     60 
     61 //____________________________________________________________________________//
     62 
     63 // ************************************************************************** //
     64 // **************                       nil                    ************** //
     65 // ************************************************************************** //
     66 
     67 struct nil {
     68     template<typename T>
     69 #if defined(__GNUC__) || defined(__HP_aCC) || defined(__EDG__) || defined(__SUNPRO_CC)
     70     operator T() const
     71 #else
     72     operator T const&() const
     73 #endif
     74     { report_access_to_invalid_parameter(); static T* v = 0; return *v; }
     75 
     76     template<typename T>
     77     T any_cast() const
     78     { report_access_to_invalid_parameter(); static typename remove_reference<T>::type* v = 0; return *v; }
     79 
     80     template<typename Arg1>
     81     nil operator()( Arg1 const& )
     82     { report_access_to_invalid_parameter(); return nil(); }
     83 
     84     template<typename Arg1,typename Arg2>
     85     nil operator()( Arg1 const&, Arg2 const& )
     86     { report_access_to_invalid_parameter(); return nil(); }
     87 
     88     template<typename Arg1,typename Arg2,typename Arg3>
     89     nil operator()( Arg1 const&, Arg2 const&, Arg3 const& )
     90     { report_access_to_invalid_parameter(); return nil(); }
     91 
     92     // Visitation support
     93     template<typename Visitor>
     94     void            apply_to( Visitor& V ) const {}
     95 
     96     static nil&     inst() { static nil s_inst; return s_inst; }
     97 private:
     98     nil() {}
     99 };
    100 
    101 // ************************************************************************** //
    102 // **************              named_parameter_base            ************** //
    103 // ************************************************************************** //
    104 
    105 template<typename Derived>
    106 struct named_parameter_base {
    107     template<typename NP>
    108     named_parameter_combine<NP,Derived>
    109     operator,( NP const& np ) const { return named_parameter_combine<NP,Derived>( np, *static_cast<Derived const*>(this) ); }
    110 };
    111 
    112 //____________________________________________________________________________//
    113 
    114 // ************************************************************************** //
    115 // **************             named_parameter_combine          ************** //
    116 // ************************************************************************** //
    117 
    118 template<typename NP, typename Rest = nil>
    119 struct named_parameter_combine
    120 : Rest
    121 , named_parameter_base<named_parameter_combine<NP,Rest> > {
    122     typedef typename NP::ref_type  res_type;
    123     typedef named_parameter_combine<NP,Rest> self_type;
    124 
    125     // Constructor
    126     named_parameter_combine( NP const& np, Rest const& r )
    127     : Rest( r )
    128     , m_param( np )
    129     {}
    130 
    131     // Access methods
    132     res_type    operator[]( keyword<typename NP::id,true> kw ) const    { return m_param[kw]; }
    133     res_type    operator[]( keyword<typename NP::id,false> kw ) const   { return m_param[kw]; }
    134     using       Rest::operator[];
    135 
    136     bool        has( keyword<typename NP::id,false> kw ) const          { return m_param.has( kw ); }
    137     using       Rest::has;
    138 
    139     void        erase( keyword<typename NP::id,false> kw ) const        { m_param.erase( kw ); }
    140     using       Rest::erase;
    141 
    142 #if BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3206)) || \
    143     BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x0610))
    144     template<typename NP>
    145     named_parameter_combine<NP,self_type> operator,( NP const& np ) const
    146     { return named_parameter_combine<NP,self_type>( np, *this ); }
    147 #else
    148     using       named_parameter_base<named_parameter_combine<NP,Rest> >::operator,;
    149 #endif
    150 
    151     // Visitation support
    152     template<typename Visitor>
    153     void            apply_to( Visitor& V ) const
    154     {
    155         m_param.apply_to( V );
    156 
    157         Rest::apply_to( V );
    158     }
    159 private:
    160     // Data members
    161     NP          m_param;
    162 };
    163 
    164 } // namespace nfp_detail
    165 
    166 // ************************************************************************** //
    167 // **************                 named_parameter              ************** //
    168 // ************************************************************************** //
    169 
    170 template<typename T, typename unique_id,typename ReferenceType=T&>
    171 struct named_parameter
    172 : nfp_detail::named_parameter_base<named_parameter<T, unique_id,ReferenceType> >
    173 {
    174     typedef nfp_detail::nil nil_t;
    175     typedef T               data_type;
    176     typedef ReferenceType   ref_type;
    177     typedef unique_id       id;
    178 
    179     // Constructor
    180     explicit        named_parameter( ref_type v )
    181     : m_value( v )
    182     , m_erased( false )
    183     {}
    184     named_parameter( named_parameter const& np )
    185     : m_value( np.m_value )
    186     , m_erased( np.m_erased )
    187     {}
    188 
    189     // Access methods
    190     ref_type        operator[]( keyword<unique_id,true> ) const     { return m_erased ? nil_t::inst().template any_cast<ref_type>() :  m_value; }
    191     ref_type        operator[]( keyword<unique_id,false> ) const    { return m_erased ? nil_t::inst().template any_cast<ref_type>() :  m_value; }
    192     template<typename UnknownId>
    193     nil_t           operator[]( keyword<UnknownId,false> ) const    { return nil_t::inst(); }
    194 
    195     bool            has( keyword<unique_id,false> ) const           { return !m_erased; }
    196     template<typename UnknownId>
    197     bool            has( keyword<UnknownId,false> ) const           { return false; }
    198 
    199     void            erase( keyword<unique_id,false> ) const         { m_erased = true; }
    200     template<typename UnknownId>
    201     void            erase( keyword<UnknownId,false> ) const         {}
    202 
    203     // Visitation support
    204     template<typename Visitor>
    205     void            apply_to( Visitor& V ) const
    206     {
    207         V.set_parameter( rtti::type_id<unique_id>(), m_value );
    208     }
    209 
    210 private:
    211     // Data members
    212     ref_type        m_value;
    213     mutable bool    m_erased;
    214 };
    215 
    216 //____________________________________________________________________________//
    217 
    218 // ************************************************************************** //
    219 // **************                    no_params                 ************** //
    220 // ************************************************************************** //
    221 
    222 namespace nfp_detail {
    223 typedef named_parameter<char, struct no_params_type_t,char> no_params_type;
    224 } // namespace nfp_detail
    225 
    226 namespace {
    227 nfp_detail::no_params_type no_params( '\0' );
    228 } // local namespace
    229 
    230 //____________________________________________________________________________//
    231 
    232 // ************************************************************************** //
    233 // **************                     keyword                  ************** //
    234 // ************************************************************************** //
    235 
    236 template<typename unique_id, bool required = false>
    237 struct keyword {
    238     typedef unique_id id;
    239 
    240     template<typename T>
    241     named_parameter<T const,unique_id>
    242     operator=( T const& t ) const       { return named_parameter<T const,unique_id>( t ); }
    243 
    244     template<typename T>
    245     named_parameter<T,unique_id>
    246     operator=( T& t ) const   { return named_parameter<T,unique_id>( t ); }
    247 
    248     named_parameter<char const*,unique_id,char const*>
    249     operator=( char const* t ) const   { return named_parameter<char const*,unique_id,char const*>( t ); }
    250 };
    251 
    252 //____________________________________________________________________________//
    253 
    254 // ************************************************************************** //
    255 // **************                  typed_keyword               ************** //
    256 // ************************************************************************** //
    257 
    258 template<typename T, typename unique_id, bool required = false>
    259 struct typed_keyword : keyword<unique_id,required> {
    260     named_parameter<T const,unique_id>
    261     operator=( T const& t ) const       { return named_parameter<T const,unique_id>( t ); }
    262 
    263     named_parameter<T,unique_id>
    264     operator=( T& t ) const             { return named_parameter<T,unique_id>( t ); }
    265 };
    266 
    267 //____________________________________________________________________________//
    268 
    269 template<typename unique_id>
    270 struct typed_keyword<bool,unique_id,false>
    271 : keyword<unique_id,false>
    272 , named_parameter<bool,unique_id,bool> {
    273     typedef unique_id id;
    274 
    275     typed_keyword() : named_parameter<bool,unique_id,bool>( true ) {}
    276 
    277     named_parameter<bool,unique_id,bool>
    278     operator!() const           { return named_parameter<bool,unique_id,bool>( false ); }
    279 };
    280 
    281 //____________________________________________________________________________//
    282 
    283 // ************************************************************************** //
    284 // **************                optionally_assign             ************** //
    285 // ************************************************************************** //
    286 
    287 template<typename T>
    288 inline void
    289 optionally_assign( T&, nfp_detail::nil )
    290 {
    291     nfp_detail::report_access_to_invalid_parameter();
    292 }
    293 
    294 //____________________________________________________________________________//
    295 
    296 template<typename T, typename Source>
    297 inline void
    298 #if BOOST_WORKAROUND( __MWERKS__, BOOST_TESTED_AT( 0x3003 ) ) \
    299     || BOOST_WORKAROUND( __DECCXX_VER, BOOST_TESTED_AT(60590042) )
    300 optionally_assign( T& target, Source src )
    301 #else
    302 optionally_assign( T& target, Source const& src )
    303 #endif
    304 {
    305     using namespace unit_test;
    306 
    307     assign_op( target, src, static_cast<int>(0) );
    308 }
    309 
    310 //____________________________________________________________________________//
    311 
    312 template<typename T, typename Params, typename Keyword>
    313 inline void
    314 optionally_assign( T& target, Params const& p, Keyword k )
    315 {
    316     if( p.has(k) )
    317         optionally_assign( target, p[k] );
    318 }
    319 
    320 //____________________________________________________________________________//
    321 
    322 } // namespace nfp
    323 
    324 } // namespace boost
    325 
    326 #include <boost/test/detail/enable_warnings.hpp>
    327 
    328 #endif // BOOST_TEST_NAMED_PARAM_022505GER
    329 
    330