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