1 //  (C) Copyright Gennadiy Rozental 2005-2008.
2 //  Use, modification, and distribution are subject to the
3 //  Boost Software License, Version 1.0. (See accompanying file
4 //  LICENSE_1_0.txt or copy at 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: 57992 $
11 //
12 //  Description : generic typed_argument_factory implementation
13 // ***************************************************************************
14 
15 #ifndef BOOST_RT_CLA_ARGUMENT_FACTORY_HPP_062604GER
16 #define BOOST_RT_CLA_ARGUMENT_FACTORY_HPP_062604GER
17 
18 // Boost.Runtime.Parameter
19 #include <boost/test/utils/runtime/config.hpp>
20 
21 #include <boost/test/utils/runtime/fwd.hpp>
22 #include <boost/test/utils/runtime/validation.hpp>
23 #include <boost/test/utils/runtime/argument.hpp>
24 #include <boost/test/utils/runtime/trace.hpp>
25 #include <boost/test/utils/runtime/interpret_argument_value.hpp>
26 
27 #include <boost/test/utils/runtime/cla/fwd.hpp>
28 #include <boost/test/utils/runtime/cla/value_generator.hpp>
29 #include <boost/test/utils/runtime/cla/value_handler.hpp>
30 #include <boost/test/utils/runtime/cla/validation.hpp>
31 #include <boost/test/utils/runtime/cla/argv_traverser.hpp>
32 #include <boost/test/utils/runtime/cla/detail/argument_value_usage.hpp>
33 
34 #include <boost/test/utils/runtime/cla/iface/argument_factory.hpp>
35 
36 // Boost.Test
37 #include <boost/test/utils/callback.hpp>
38 
39 // Boost
40 #include <boost/optional.hpp>
41 
42 namespace boost {
43 
44 namespace BOOST_RT_PARAM_NAMESPACE {
45 
46 namespace cla {
47 
48 // ************************************************************************** //
49 // **************           default_value_interpreter          ************** //
50 // ************************************************************************** //
51 
52 namespace rt_cla_detail {
53 
54 struct default_value_interpreter {
55     template<typename T>
operator ()boost::BOOST_RT_PARAM_NAMESPACE::cla::rt_cla_detail::default_value_interpreter56     void operator()( argv_traverser& tr, boost::optional<T>& value )
57     {
58         if( interpret_argument_value( tr.token(), value, 0 ) )
59             tr.next_token();
60     }
61 };
62 
63 } // namespace rt_cla_detail
64 
65 // ************************************************************************** //
66 // **************             typed_argument_factory           ************** //
67 // ************************************************************************** //
68 
69 template<typename T>
70 struct typed_argument_factory : public argument_factory {
71     // Constructor
typed_argument_factoryboost::BOOST_RT_PARAM_NAMESPACE::cla::typed_argument_factory72     typed_argument_factory()
73     : m_value_interpreter( rt_cla_detail::default_value_interpreter() )
74     {}
~typed_argument_factoryboost::BOOST_RT_PARAM_NAMESPACE::cla::typed_argument_factory75     BOOST_RT_PARAM_UNNEEDED_VIRTUAL ~typed_argument_factory() {}
76 
77     // properties modification
78     template<typename Modifier>
accept_modifierboost::BOOST_RT_PARAM_NAMESPACE::cla::typed_argument_factory79     void                accept_modifier( Modifier const& m )
80     {
81         optionally_assign( m_value_handler, m, handler );
82         optionally_assign( m_value_interpreter, m, interpreter );
83 
84         if( m.has( default_value ) ) {
85             BOOST_RT_PARAM_VALIDATE_LOGIC( !m_value_generator,
86                 BOOST_RT_PARAM_LITERAL( "multiple value generators for parameter" ) );
87 
88             T const& dv_ref = m[default_value];
89             m_value_generator = rt_cla_detail::const_generator<T>( dv_ref );
90         }
91 
92         if( m.has( default_refer_to ) ) {
93             BOOST_RT_PARAM_VALIDATE_LOGIC( !m_value_generator,
94                 BOOST_RT_PARAM_LITERAL( "multiple value generators for parameter" ) );
95 
96             cstring ref_id = m[default_refer_to];
97             m_value_generator = rt_cla_detail::ref_generator<T>( ref_id );
98         }
99 
100         if( m.has( assign_to ) ) {
101             BOOST_RT_PARAM_VALIDATE_LOGIC( !m_value_handler,
102                 BOOST_RT_PARAM_LITERAL( "multiple value handlers for parameter" ) );
103 
104             m_value_handler = rt_cla_detail::assigner<T>( m[assign_to] );
105         }
106     }
107 
108     // Argument factory implementation
109     virtual argument_ptr produce_using( parameter& p, argv_traverser& tr );
110     virtual argument_ptr produce_using( parameter& p, parser const& );
111     virtual void         argument_usage_info( format_stream& fs );
112 
113 // !! private?
114     // Data members
115     unit_test::callback2<parameter const&,T&>                   m_value_handler;
116     unit_test::callback2<parser const&,boost::optional<T>&>     m_value_generator;
117     unit_test::callback2<argv_traverser&,boost::optional<T>&>   m_value_interpreter;
118 };
119 
120 //____________________________________________________________________________//
121 
122 template<typename T>
123 inline argument_ptr
produce_using(parameter & p,argv_traverser & tr)124 typed_argument_factory<T>::produce_using( parameter& p, argv_traverser& tr )
125 {
126     boost::optional<T> value;
127 
128     try {
129         m_value_interpreter( tr, value );
130     }
131     catch( ... ) { // !! should we do that?
132         BOOST_RT_PARAM_TRACE( "Fail to parse argument value" );
133 
134         if( !p.p_optional_value )
135             throw;
136     }
137 
138     argument_ptr actual_arg = p.actual_argument();
139 
140     BOOST_RT_CLA_VALIDATE_INPUT( !!value || p.p_optional_value, tr,
141         BOOST_RT_PARAM_LITERAL( "Argument value missing for parameter " ) << p.id_2_report() );
142 
143     BOOST_RT_CLA_VALIDATE_INPUT( !actual_arg || p.p_multiplicable, tr,
144         BOOST_RT_PARAM_LITERAL( "Unexpected repetition of the parameter " ) << p.id_2_report() );
145 
146     if( !!value && !!m_value_handler )
147         m_value_handler( p, *value );
148 
149     if( !p.p_multiplicable )
150         actual_arg.reset( p.p_optional_value && (rtti::type_id<T>() != rtti::type_id<bool>())
151             ? static_cast<argument*>(new typed_argument<boost::optional<T> >( p, value ))
152             : static_cast<argument*>(new typed_argument<T>( p, *value )) );
153     else {
154         typedef std::list<boost::optional<T> > optional_list;
155 
156         if( !actual_arg )
157             actual_arg.reset( p.p_optional_value
158                 ? static_cast<argument*>(new typed_argument<optional_list>( p ))
159                 : static_cast<argument*>(new typed_argument<std::list<T> >( p )) );
160 
161         if( p.p_optional_value ) {
162             optional_list& values = arg_value<optional_list>( *actual_arg );
163 
164             values.push_back( value );
165         }
166         else {
167             std::list<T>& values = arg_value<std::list<T> >( *actual_arg );
168 
169             values.push_back( *value );
170         }
171     }
172 
173     return actual_arg;
174 }
175 
176 //____________________________________________________________________________//
177 
178 template<typename T>
179 inline argument_ptr
produce_using(parameter & p,parser const & pa)180 typed_argument_factory<T>::produce_using( parameter& p, parser const& pa )
181 {
182     argument_ptr actual_arg;
183 
184     if( !m_value_generator )
185         return actual_arg;
186 
187     boost::optional<T> value;
188     m_value_generator( pa, value );
189 
190     if( !value )
191         return actual_arg;
192 
193     if( !!m_value_handler )
194         m_value_handler( p, *value );
195 
196     actual_arg.reset( new typed_argument<T>( p, *value ) );
197 
198     return actual_arg;
199 }
200 
201 //____________________________________________________________________________//
202 
203 template<typename T>
204 inline void
argument_usage_info(format_stream & fs)205 typed_argument_factory<T>::argument_usage_info( format_stream& fs )
206 {
207     rt_cla_detail::argument_value_usage( fs, 0, reinterpret_cast<T*>(0) );
208 }
209 
210 //____________________________________________________________________________//
211 
212 } // namespace boost
213 
214 } // namespace BOOST_RT_PARAM_NAMESPACE
215 
216 } // namespace cla
217 
218 #endif // BOOST_RT_CLA_ARGUMENT_FACTORY_HPP_062604GER
219