]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // Copyright Daniel Wallin, David Abrahams 2005. Use, modification and |
2 | // distribution is subject to the Boost Software License, Version 1.0. (See | |
3 | // accompanying file LICENSE_1_0.txt or copy at | |
4 | // http://www.boost.org/LICENSE_1_0.txt) | |
5 | ||
6 | #ifndef ARG_LIST_050329_HPP | |
7 | #define ARG_LIST_050329_HPP | |
8 | ||
9 | #include <boost/parameter/aux_/void.hpp> | |
10 | #include <boost/parameter/aux_/result_of0.hpp> | |
11 | #include <boost/parameter/aux_/default.hpp> | |
12 | #include <boost/parameter/aux_/parameter_requirements.hpp> | |
13 | #include <boost/parameter/aux_/yesno.hpp> | |
14 | #include <boost/parameter/aux_/is_maybe.hpp> | |
15 | #include <boost/parameter/config.hpp> | |
16 | ||
17 | #include <boost/mpl/apply.hpp> | |
18 | #include <boost/mpl/assert.hpp> | |
19 | #include <boost/mpl/begin.hpp> | |
20 | #include <boost/mpl/end.hpp> | |
21 | #include <boost/mpl/iterator_tags.hpp> | |
22 | ||
23 | #include <boost/type_traits/add_reference.hpp> | |
24 | #include <boost/type_traits/is_same.hpp> | |
25 | #include <boost/preprocessor/repetition/enum_params.hpp> | |
26 | #include <boost/preprocessor/repetition/enum_binary_params.hpp> | |
27 | #include <boost/preprocessor/facilities/intercept.hpp> | |
28 | ||
29 | namespace boost { namespace parameter { | |
30 | ||
31 | // Forward declaration for aux::arg_list, below. | |
32 | template<class T> struct keyword; | |
33 | ||
34 | namespace aux { | |
35 | ||
36 | // Tag type passed to MPL lambda. | |
37 | struct lambda_tag; | |
38 | ||
39 | // | |
40 | // Structures used to build the tuple of actual arguments. The | |
41 | // tuple is a nested cons-style list of arg_list specializations | |
42 | // terminated by an empty_arg_list. | |
43 | // | |
44 | // Each specialization of arg_list is derived from its successor in | |
45 | // the list type. This feature is used along with using | |
46 | // declarations to build member function overload sets that can | |
47 | // match against keywords. | |
48 | // | |
49 | ||
50 | // MPL sequence support | |
51 | struct arg_list_tag; | |
52 | ||
53 | // Terminates arg_list<> and represents an empty list. Since this | |
54 | // is just the terminating case you might want to look at arg_list | |
55 | // first, to get a feel for what's really happening here. | |
56 | ||
57 | struct empty_arg_list | |
58 | { | |
59 | empty_arg_list() {} | |
60 | ||
61 | // Constructor taking BOOST_PARAMETER_MAX_ARITY empty_arg_list | |
62 | // arguments; this makes initialization | |
63 | empty_arg_list( | |
64 | BOOST_PP_ENUM_PARAMS( | |
65 | BOOST_PARAMETER_MAX_ARITY, void_ BOOST_PP_INTERCEPT | |
66 | )) | |
67 | {} | |
68 | ||
69 | // A metafunction class that, given a keyword and a default | |
70 | // type, returns the appropriate result type for a keyword | |
71 | // lookup given that default | |
72 | struct binding | |
73 | { | |
74 | template<class KW, class Default, class Reference> | |
75 | struct apply | |
76 | { | |
77 | typedef Default type; | |
78 | }; | |
79 | }; | |
80 | ||
81 | // Terminator for has_key, indicating that the keyword is unique | |
82 | template <class KW> | |
83 | static no_tag has_key(KW*); | |
84 | ||
85 | #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) | |
86 | ||
87 | // The overload set technique doesn't work with these older | |
88 | // compilers, so they need some explicit handholding. | |
89 | ||
90 | // A metafunction class that, given a keyword, returns the type | |
91 | // of the base sublist whose get() function can produce the | |
92 | // value for that key | |
93 | struct key_owner | |
94 | { | |
95 | template<class KW> | |
96 | struct apply | |
97 | { | |
98 | typedef empty_arg_list type; | |
99 | }; | |
100 | }; | |
101 | ||
102 | template <class K, class T> | |
103 | T& get(default_<K,T> x) const | |
104 | { | |
105 | return x.value; | |
106 | } | |
107 | ||
108 | template <class K, class F> | |
109 | typename result_of0<F>::type | |
110 | get(lazy_default<K,F> x) const | |
111 | { | |
112 | return x.compute_default(); | |
113 | } | |
114 | #endif | |
115 | ||
116 | // If this function is called, it means there is no argument | |
117 | // in the list that matches the supplied keyword. Just return | |
118 | // the default value. | |
119 | template <class K, class Default> | |
120 | Default& operator[](default_<K, Default> x) const | |
121 | { | |
122 | return x.value; | |
123 | } | |
124 | ||
125 | // If this function is called, it means there is no argument | |
126 | // in the list that matches the supplied keyword. Just evaluate | |
127 | // and return the default value. | |
128 | template <class K, class F> | |
129 | typename result_of0<F>::type | |
130 | operator[]( | |
131 | BOOST_PARAMETER_lazy_default_fallback<K,F> x) const | |
132 | { | |
133 | return x.compute_default(); | |
134 | } | |
135 | ||
136 | // No argument corresponding to ParameterRequirements::key_type | |
137 | // was found if we match this overload, so unless that parameter | |
138 | // has a default, we indicate that the actual arguments don't | |
139 | // match the function's requirements. | |
140 | template <class ParameterRequirements, class ArgPack> | |
141 | static typename ParameterRequirements::has_default | |
142 | satisfies(ParameterRequirements*, ArgPack*); | |
143 | ||
144 | // MPL sequence support | |
145 | typedef empty_arg_list type; // convenience | |
146 | typedef arg_list_tag tag; // For dispatching to sequence intrinsics | |
147 | }; | |
148 | ||
149 | // Forward declaration for arg_list::operator, | |
150 | template <class KW, class T> | |
151 | struct tagged_argument; | |
152 | ||
153 | template <class T> | |
154 | struct get_reference | |
155 | { | |
156 | typedef typename T::reference type; | |
157 | }; | |
158 | ||
159 | // A tuple of tagged arguments, terminated with empty_arg_list. | |
160 | // Every TaggedArg is an instance of tagged_argument<>. | |
161 | template <class TaggedArg, class Next = empty_arg_list> | |
162 | struct arg_list : Next | |
163 | { | |
164 | typedef arg_list<TaggedArg,Next> self; | |
165 | typedef typename TaggedArg::key_type key_type; | |
166 | ||
167 | typedef typename is_maybe<typename TaggedArg::value_type>::type holds_maybe; | |
168 | ||
169 | typedef typename mpl::eval_if< | |
170 | holds_maybe | |
171 | , get_reference<typename TaggedArg::value_type> | |
172 | , get_reference<TaggedArg> | |
173 | >::type reference; | |
174 | ||
175 | typedef typename mpl::if_< | |
176 | holds_maybe | |
177 | , reference | |
178 | , typename TaggedArg::value_type | |
179 | >::type value_type; | |
180 | ||
181 | TaggedArg arg; // Stores the argument | |
182 | ||
183 | // Store the arguments in successive nodes of this list | |
184 | template< // class A0, class A1, ... | |
185 | BOOST_PP_ENUM_PARAMS(BOOST_PARAMETER_MAX_ARITY, class A) | |
186 | > | |
187 | arg_list( // A0& a0, A1& a1, ... | |
188 | BOOST_PP_ENUM_BINARY_PARAMS(BOOST_PARAMETER_MAX_ARITY, A, & a) | |
189 | ) | |
190 | : Next( // a1, a2, ... | |
191 | BOOST_PP_ENUM_SHIFTED_PARAMS(BOOST_PARAMETER_MAX_ARITY, a) | |
192 | , void_reference() | |
193 | ) | |
194 | , arg(a0) | |
195 | {} | |
196 | ||
197 | // Create a new list by prepending arg to a copy of tail. Used | |
198 | // when incrementally building this structure with the comma | |
199 | // operator. | |
200 | arg_list(TaggedArg head, Next const& tail) | |
201 | : Next(tail) | |
202 | , arg(head) | |
203 | {} | |
204 | ||
205 | // A metafunction class that, given a keyword and a default | |
206 | // type, returns the appropriate result type for a keyword | |
207 | // lookup given that default | |
208 | struct binding | |
209 | { | |
210 | template <class KW, class Default, class Reference> | |
211 | struct apply | |
212 | { | |
213 | typedef typename mpl::eval_if< | |
214 | boost::is_same<KW, key_type> | |
215 | , mpl::if_<Reference, reference, value_type> | |
216 | , mpl::apply_wrap3<typename Next::binding, KW, Default, Reference> | |
217 | >::type type; | |
218 | }; | |
219 | }; | |
220 | ||
221 | #if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) | |
222 | // Overload for key_type, so the assert below will fire if the | |
223 | // same keyword is used again | |
224 | static yes_tag has_key(key_type*); | |
225 | using Next::has_key; | |
226 | ||
227 | BOOST_MPL_ASSERT_MSG( | |
228 | sizeof(Next::has_key((key_type*)0)) == sizeof(no_tag) | |
229 | , duplicate_keyword, (key_type) | |
230 | ); | |
231 | ||
232 | #endif | |
233 | // | |
234 | // Begin implementation of indexing operators for looking up | |
235 | // specific arguments by name | |
236 | // | |
237 | ||
238 | // Helpers that handle the case when TaggedArg is | |
239 | // empty<T>. | |
240 | template <class D> | |
241 | reference get_default(D const&, mpl::false_) const | |
242 | { | |
243 | return arg.value; | |
244 | } | |
245 | ||
246 | template <class D> | |
247 | reference get_default(D const& d, mpl::true_) const | |
248 | { | |
249 | return arg.value ? arg.value.get() : arg.value.construct(d.value); | |
250 | } | |
251 | ||
252 | #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) | |
253 | // These older compilers don't support the overload set creation | |
254 | // idiom well, so we need to do all the return type calculation | |
255 | // for the compiler and dispatch through an outer function template | |
256 | ||
257 | // A metafunction class that, given a keyword, returns the base | |
258 | // sublist whose get() function can produce the value for that | |
259 | // key. | |
260 | struct key_owner | |
261 | { | |
262 | template<class KW> | |
263 | struct apply | |
264 | { | |
265 | typedef typename mpl::eval_if< | |
266 | boost::is_same<KW, key_type> | |
267 | , mpl::identity<arg_list<TaggedArg,Next> > | |
268 | , mpl::apply_wrap1<typename Next::key_owner,KW> | |
269 | >::type type; | |
270 | }; | |
271 | }; | |
272 | ||
273 | // Outer indexing operators that dispatch to the right node's | |
274 | // get() function. | |
275 | template <class KW> | |
276 | typename mpl::apply_wrap3<binding, KW, void_, mpl::true_>::type | |
277 | operator[](keyword<KW> const& x) const | |
278 | { | |
279 | typename mpl::apply_wrap1<key_owner, KW>::type const& sublist = *this; | |
280 | return sublist.get(x); | |
281 | } | |
282 | ||
283 | template <class KW, class Default> | |
284 | typename mpl::apply_wrap3<binding, KW, Default&, mpl::true_>::type | |
285 | operator[](default_<KW, Default> x) const | |
286 | { | |
287 | typename mpl::apply_wrap1<key_owner, KW>::type const& sublist = *this; | |
288 | return sublist.get(x); | |
289 | } | |
290 | ||
291 | template <class KW, class F> | |
292 | typename mpl::apply_wrap3< | |
293 | binding,KW | |
294 | , typename result_of0<F>::type | |
295 | , mpl::true_ | |
296 | >::type | |
297 | operator[](lazy_default<KW,F> x) const | |
298 | { | |
299 | typename mpl::apply_wrap1<key_owner, KW>::type const& sublist = *this; | |
300 | return sublist.get(x); | |
301 | } | |
302 | ||
303 | // These just return the stored value; when empty_arg_list is | |
304 | // reached, indicating no matching argument was passed, the | |
305 | // default is returned, or if no default_ or lazy_default was | |
306 | // passed, compilation fails. | |
307 | reference get(keyword<key_type> const&) const | |
308 | { | |
309 | BOOST_MPL_ASSERT_NOT((holds_maybe)); | |
310 | return arg.value; | |
311 | } | |
312 | ||
313 | template <class Default> | |
314 | reference get(default_<key_type,Default> const& d) const | |
315 | { | |
316 | return get_default(d, holds_maybe()); | |
317 | } | |
318 | ||
319 | template <class Default> | |
320 | reference get(lazy_default<key_type, Default>) const | |
321 | { | |
322 | return arg.value; | |
323 | } | |
324 | ||
325 | #else | |
326 | ||
327 | reference operator[](keyword<key_type> const&) const | |
328 | { | |
329 | BOOST_MPL_ASSERT_NOT((holds_maybe)); | |
330 | return arg.value; | |
331 | } | |
332 | ||
333 | template <class Default> | |
334 | reference operator[](default_<key_type, Default> const& d) const | |
335 | { | |
336 | return get_default(d, holds_maybe()); | |
337 | } | |
338 | ||
339 | template <class Default> | |
340 | reference operator[](lazy_default<key_type, Default>) const | |
341 | { | |
342 | return arg.value; | |
343 | } | |
344 | ||
345 | // Builds an overload set including operator[]s defined in base | |
346 | // classes. | |
347 | using Next::operator[]; | |
348 | ||
349 | // | |
350 | // End of indexing support | |
351 | // | |
352 | ||
353 | ||
354 | // | |
355 | // For parameter_requirements matching this node's key_type, | |
356 | // return a bool constant wrapper indicating whether the | |
357 | // requirements are satisfied by TaggedArg. Used only for | |
358 | // compile-time computation and never really called, so a | |
359 | // declaration is enough. | |
360 | // | |
361 | template <class HasDefault, class Predicate, class ArgPack> | |
362 | static typename mpl::apply_wrap2< | |
363 | typename mpl::lambda<Predicate, lambda_tag>::type | |
364 | , value_type, ArgPack | |
365 | >::type | |
366 | satisfies( | |
367 | parameter_requirements<key_type,Predicate,HasDefault>* | |
368 | , ArgPack* | |
369 | ); | |
370 | ||
371 | // Builds an overload set including satisfies functions defined | |
372 | // in base classes. | |
373 | using Next::satisfies; | |
374 | #endif | |
375 | ||
376 | // Comma operator to compose argument list without using parameters<>. | |
377 | // Useful for argument lists with undetermined length. | |
378 | template <class KW, class T2> | |
379 | arg_list<tagged_argument<KW, T2>, self> | |
380 | operator,(tagged_argument<KW,T2> x) const | |
381 | { | |
382 | return arg_list<tagged_argument<KW,T2>, self>(x, *this); | |
383 | } | |
384 | ||
385 | // MPL sequence support | |
386 | typedef self type; // Convenience for users | |
387 | typedef Next tail_type; // For the benefit of iterators | |
388 | typedef arg_list_tag tag; // For dispatching to sequence intrinsics | |
389 | }; | |
390 | ||
391 | // MPL sequence support | |
392 | template <class ArgumentPack> | |
393 | struct arg_list_iterator | |
394 | { | |
395 | typedef mpl::forward_iterator_tag category; | |
396 | ||
397 | // The incremented iterator | |
398 | typedef arg_list_iterator<typename ArgumentPack::tail_type> next; | |
399 | ||
400 | // dereferencing yields the key type | |
401 | typedef typename ArgumentPack::key_type type; | |
402 | }; | |
403 | ||
404 | template <> | |
405 | struct arg_list_iterator<empty_arg_list> {}; | |
406 | ||
407 | }} // namespace parameter::aux | |
408 | ||
409 | // MPL sequence support | |
410 | namespace mpl | |
411 | { | |
412 | template <> | |
413 | struct begin_impl<parameter::aux::arg_list_tag> | |
414 | { | |
415 | template <class S> | |
416 | struct apply | |
417 | { | |
418 | typedef parameter::aux::arg_list_iterator<S> type; | |
419 | }; | |
420 | }; | |
421 | ||
422 | template <> | |
423 | struct end_impl<parameter::aux::arg_list_tag> | |
424 | { | |
425 | template <class> | |
426 | struct apply | |
427 | { | |
428 | typedef parameter::aux::arg_list_iterator<parameter::aux::empty_arg_list> type; | |
429 | }; | |
430 | }; | |
431 | } | |
432 | ||
433 | } // namespace boost | |
434 | ||
435 | #endif // ARG_LIST_050329_HPP | |
436 |