]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /////////////////////////////////////////////////////////////////////////////// |
2 | /// \file functional.hpp | |
3 | /// | |
4 | // Copyright 2005 Eric Niebler. Distributed under the Boost | |
5 | // Software License, Version 1.0. (See accompanying file | |
6 | // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
7 | ||
8 | #ifndef BOOST_NUMERIC_FUNCTIONAL_HPP_EAN_08_12_2005 | |
9 | #define BOOST_NUMERIC_FUNCTIONAL_HPP_EAN_08_12_2005 | |
10 | ||
11 | #include <limits> | |
12 | #include <functional> | |
13 | #include <boost/static_assert.hpp> | |
14 | #include <boost/mpl/if.hpp> | |
15 | #include <boost/mpl/and.hpp> | |
16 | #include <boost/type_traits/remove_const.hpp> | |
17 | #include <boost/type_traits/add_reference.hpp> | |
18 | #include <boost/type_traits/is_empty.hpp> | |
19 | #include <boost/type_traits/is_integral.hpp> | |
20 | #include <boost/type_traits/is_floating_point.hpp> | |
21 | #include <boost/utility/enable_if.hpp> | |
22 | #include <boost/typeof/typeof.hpp> | |
23 | #include <boost/accumulators/accumulators_fwd.hpp> | |
24 | #include <boost/accumulators/numeric/functional_fwd.hpp> | |
25 | #include <boost/accumulators/numeric/detail/function1.hpp> | |
26 | #include <boost/accumulators/numeric/detail/function2.hpp> | |
27 | #include <boost/accumulators/numeric/detail/pod_singleton.hpp> | |
28 | ||
29 | #ifdef BOOST_NUMERIC_FUNCTIONAL_STD_VECTOR_SUPPORT | |
30 | # include <boost/accumulators/numeric/functional/vector.hpp> | |
31 | #endif | |
32 | ||
33 | #ifdef BOOST_NUMERIC_FUNCTIONAL_STD_VALARRAY_SUPPORT | |
34 | # include <boost/accumulators/numeric/functional/valarray.hpp> | |
35 | #endif | |
36 | ||
37 | #ifdef BOOST_NUMERIC_FUNCTIONAL_STD_COMPLEX_SUPPORT | |
38 | # include <boost/accumulators/numeric/functional/complex.hpp> | |
39 | #endif | |
40 | ||
41 | /// INTERNAL ONLY | |
42 | /// | |
43 | #define BOOST_NUMERIC_FUNCTIONAL_HPP_INCLUDED | |
44 | ||
45 | #ifdef BOOST_NUMERIC_FUNCTIONAL_DOXYGEN_INVOKED | |
46 | // Hack to make Doxygen show the inheritance relationships | |
47 | /// INTERNAL ONLY | |
48 | /// | |
49 | namespace std | |
50 | { | |
51 | /// INTERNAL ONLY | |
52 | /// | |
53 | template<class Arg, class Ret> struct unary_function {}; | |
54 | /// INTERNAL ONLY | |
55 | /// | |
56 | template<class Left, class Right, class Ret> struct binary_function {}; | |
57 | } | |
58 | #endif | |
59 | ||
60 | namespace boost { namespace numeric | |
61 | { | |
62 | namespace functional | |
63 | { | |
64 | /// INTERNAL ONLY | |
65 | /// | |
66 | template<typename A0, typename A1> | |
67 | struct are_integral | |
68 | : mpl::and_<is_integral<A0>, is_integral<A1> > | |
69 | {}; | |
70 | ||
71 | template<typename Left, typename Right> | |
72 | struct left_ref | |
73 | { | |
74 | typedef Left &type; | |
75 | }; | |
76 | ||
77 | namespace detail | |
78 | { | |
79 | template<typename T> | |
80 | T &lvalue_of(); | |
81 | } | |
82 | } | |
83 | ||
84 | // TODO: handle complex weight, valarray, MTL vectors | |
85 | ||
86 | /// INTERNAL ONLY | |
87 | /// | |
88 | #define BOOST_NUMERIC_FUNCTIONAL_DEFINE_UNARY_OP(Name, Op) \ | |
89 | namespace functional \ | |
90 | { \ | |
91 | template<typename Arg> \ | |
92 | struct result_of_ ## Name \ | |
93 | { \ | |
94 | BOOST_TYPEOF_NESTED_TYPEDEF_TPL( \ | |
95 | nested \ | |
96 | , Op boost::numeric::functional::detail::lvalue_of<Arg>() \ | |
97 | ) \ | |
98 | typedef typename nested::type type; \ | |
99 | }; \ | |
100 | template<typename Arg, typename EnableIf> \ | |
101 | struct Name ## _base \ | |
102 | : std::unary_function< \ | |
103 | typename remove_const<Arg>::type \ | |
104 | , typename result_of_ ## Name<Arg>::type \ | |
105 | > \ | |
106 | { \ | |
107 | typename result_of_ ## Name<Arg>::type operator ()(Arg &arg) const \ | |
108 | { \ | |
109 | return Op arg; \ | |
110 | } \ | |
111 | }; \ | |
112 | template<typename Arg, typename ArgTag> \ | |
113 | struct Name \ | |
114 | : Name ## _base<Arg, void> \ | |
115 | {}; \ | |
116 | } \ | |
117 | namespace op \ | |
118 | { \ | |
119 | struct Name \ | |
120 | : boost::detail::function1<functional::Name<_, functional::tag<_> > > \ | |
121 | {}; \ | |
122 | } \ | |
123 | namespace \ | |
124 | { \ | |
125 | op::Name const &Name = boost::detail::pod_singleton<op::Name>::instance; \ | |
126 | } \ | |
127 | /**/ | |
128 | ||
129 | /// INTERNAL ONLY | |
130 | /// | |
131 | #define BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(Name, Op, RetType) \ | |
132 | namespace functional \ | |
133 | { \ | |
134 | template<typename Left, typename Right, typename EnableIf> \ | |
135 | struct result_of_ ## Name \ | |
136 | { \ | |
137 | RetType(Left, Op, Right) \ | |
138 | }; \ | |
139 | template<typename Left, typename Right, typename EnableIf> \ | |
140 | struct Name ## _base \ | |
141 | : std::binary_function< \ | |
142 | typename remove_const<Left>::type \ | |
143 | , typename remove_const<Right>::type \ | |
144 | , typename result_of_ ## Name<Left, Right>::type \ | |
145 | > \ | |
146 | { \ | |
147 | typename result_of_ ## Name<Left, Right>::type \ | |
148 | operator ()(Left &left, Right &right) const \ | |
149 | { \ | |
150 | return left Op right; \ | |
151 | } \ | |
152 | }; \ | |
153 | template<typename Left, typename Right, typename LeftTag, typename RightTag> \ | |
154 | struct Name \ | |
155 | : Name ## _base<Left, Right, void> \ | |
156 | {}; \ | |
157 | } \ | |
158 | namespace op \ | |
159 | { \ | |
160 | struct Name \ | |
161 | : boost::detail::function2< \ | |
162 | functional::Name<_1, _2, functional::tag<_1>, functional::tag<_2> > \ | |
163 | > \ | |
164 | {}; \ | |
165 | } \ | |
166 | namespace \ | |
167 | { \ | |
168 | op::Name const &Name = boost::detail::pod_singleton<op::Name>::instance; \ | |
169 | } \ | |
170 | BOOST_ACCUMULATORS_IGNORE_GLOBAL(Name) \ | |
171 | /**/ | |
172 | ||
173 | /// INTERNAL ONLY | |
174 | /// | |
175 | #define BOOST_NUMERIC_FUNCTIONAL_DEDUCED(Left, Op, Right) \ | |
176 | BOOST_TYPEOF_NESTED_TYPEDEF_TPL( \ | |
177 | nested \ | |
178 | , boost::numeric::functional::detail::lvalue_of<Left>() Op \ | |
179 | boost::numeric::functional::detail::lvalue_of<Right>() \ | |
180 | ) \ | |
181 | typedef typename nested::type type; \ | |
182 | /**/ | |
183 | ||
184 | /// INTERNAL ONLY | |
185 | /// | |
186 | #define BOOST_NUMERIC_FUNCTIONAL_LEFT(Left, Op, Right) \ | |
187 | typedef Left &type; \ | |
188 | /**/ | |
189 | ||
190 | BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(plus, +, BOOST_NUMERIC_FUNCTIONAL_DEDUCED) | |
191 | BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(minus, -, BOOST_NUMERIC_FUNCTIONAL_DEDUCED) | |
192 | BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(multiplies, *, BOOST_NUMERIC_FUNCTIONAL_DEDUCED) | |
193 | BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(divides, /, BOOST_NUMERIC_FUNCTIONAL_DEDUCED) | |
194 | BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(modulus, %, BOOST_NUMERIC_FUNCTIONAL_DEDUCED) | |
195 | BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(greater, >, BOOST_NUMERIC_FUNCTIONAL_DEDUCED) | |
196 | BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(greater_equal, >=, BOOST_NUMERIC_FUNCTIONAL_DEDUCED) | |
197 | BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(less, <, BOOST_NUMERIC_FUNCTIONAL_DEDUCED) | |
198 | BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(less_equal, <=, BOOST_NUMERIC_FUNCTIONAL_DEDUCED) | |
199 | BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(equal_to, ==, BOOST_NUMERIC_FUNCTIONAL_DEDUCED) | |
200 | BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(not_equal_to, !=, BOOST_NUMERIC_FUNCTIONAL_DEDUCED) | |
201 | ||
202 | BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(assign, =, BOOST_NUMERIC_FUNCTIONAL_LEFT) | |
203 | BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(plus_assign, +=, BOOST_NUMERIC_FUNCTIONAL_LEFT) | |
204 | BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(minus_assign, -=, BOOST_NUMERIC_FUNCTIONAL_LEFT) | |
205 | BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(multiplies_assign, *=, BOOST_NUMERIC_FUNCTIONAL_LEFT) | |
206 | BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(divides_assign, /=, BOOST_NUMERIC_FUNCTIONAL_LEFT) | |
207 | BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(modulus_assign, %=, BOOST_NUMERIC_FUNCTIONAL_LEFT) | |
208 | ||
209 | BOOST_NUMERIC_FUNCTIONAL_DEFINE_UNARY_OP(unary_plus, +) | |
210 | BOOST_NUMERIC_FUNCTIONAL_DEFINE_UNARY_OP(unary_minus, -) | |
211 | BOOST_NUMERIC_FUNCTIONAL_DEFINE_UNARY_OP(complement, ~) | |
212 | BOOST_NUMERIC_FUNCTIONAL_DEFINE_UNARY_OP(logical_not, !) | |
213 | ||
214 | #undef BOOST_NUMERIC_FUNCTIONAL_LEFT | |
215 | #undef BOOST_NUMERIC_FUNCTIONAL_DEDUCED | |
216 | #undef BOOST_NUMERIC_FUNCTIONAL_DEFINE_UNARY_OP | |
217 | #undef BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP | |
218 | ||
219 | namespace functional | |
220 | { | |
221 | template<typename Left, typename Right, typename EnableIf> | |
222 | struct min_assign_base | |
223 | : std::binary_function<Left, Right, void> | |
224 | { | |
225 | void operator ()(Left &left, Right &right) const | |
226 | { | |
227 | if(numeric::less(right, left)) | |
228 | { | |
229 | left = right; | |
230 | } | |
231 | } | |
232 | }; | |
233 | ||
234 | template<typename Left, typename Right, typename EnableIf> | |
235 | struct max_assign_base | |
236 | : std::binary_function<Left, Right, void> | |
237 | { | |
238 | void operator ()(Left &left, Right &right) const | |
239 | { | |
240 | if(numeric::greater(right, left)) | |
241 | { | |
242 | left = right; | |
243 | } | |
244 | } | |
245 | }; | |
246 | ||
247 | template<typename Left, typename Right, typename EnableIf> | |
248 | struct fdiv_base | |
249 | : functional::divides<Left, Right> | |
250 | {}; | |
251 | ||
252 | // partial specialization that promotes the arguments to double for | |
253 | // integral division. | |
254 | template<typename Left, typename Right> | |
255 | struct fdiv_base<Left, Right, typename enable_if<are_integral<Left, Right> >::type> | |
256 | : functional::divides<double const, double const> | |
257 | {}; | |
258 | ||
259 | template<typename To, typename From, typename EnableIf> | |
260 | struct promote_base | |
261 | : std::unary_function<From, To> | |
262 | { | |
263 | To operator ()(From &from) const | |
264 | { | |
265 | return from; | |
266 | } | |
267 | }; | |
268 | ||
269 | template<typename ToFrom> | |
270 | struct promote_base<ToFrom, ToFrom, void> | |
271 | : std::unary_function<ToFrom, ToFrom> | |
272 | { | |
273 | ToFrom &operator ()(ToFrom &tofrom) | |
274 | { | |
275 | return tofrom; | |
276 | } | |
277 | }; | |
278 | ||
279 | template<typename Arg, typename EnableIf> | |
280 | struct as_min_base | |
281 | : std::unary_function<Arg, typename remove_const<Arg>::type> | |
282 | { | |
283 | BOOST_STATIC_ASSERT(std::numeric_limits<typename remove_const<Arg>::type>::is_specialized); | |
284 | ||
285 | typename remove_const<Arg>::type operator ()(Arg &) const | |
286 | { | |
287 | return (std::numeric_limits<typename remove_const<Arg>::type>::min)(); | |
288 | } | |
289 | }; | |
290 | ||
291 | template<typename Arg> | |
292 | struct as_min_base<Arg, typename enable_if<is_floating_point<Arg> >::type> | |
293 | : std::unary_function<Arg, typename remove_const<Arg>::type> | |
294 | { | |
295 | BOOST_STATIC_ASSERT(std::numeric_limits<typename remove_const<Arg>::type>::is_specialized); | |
296 | ||
297 | typename remove_const<Arg>::type operator ()(Arg &) const | |
298 | { | |
299 | return -(std::numeric_limits<typename remove_const<Arg>::type>::max)(); | |
300 | } | |
301 | }; | |
302 | ||
303 | template<typename Arg, typename EnableIf> | |
304 | struct as_max_base | |
305 | : std::unary_function<Arg, typename remove_const<Arg>::type> | |
306 | { | |
307 | BOOST_STATIC_ASSERT(std::numeric_limits<typename remove_const<Arg>::type>::is_specialized); | |
308 | ||
309 | typename remove_const<Arg>::type operator ()(Arg &) const | |
310 | { | |
311 | return (std::numeric_limits<typename remove_const<Arg>::type>::max)(); | |
312 | } | |
313 | }; | |
314 | ||
315 | template<typename Arg, typename EnableIf> | |
316 | struct as_zero_base | |
317 | : std::unary_function<Arg, typename remove_const<Arg>::type> | |
318 | { | |
319 | typename remove_const<Arg>::type operator ()(Arg &) const | |
320 | { | |
321 | return numeric::zero<typename remove_const<Arg>::type>::value; | |
322 | } | |
323 | }; | |
324 | ||
325 | template<typename Arg, typename EnableIf> | |
326 | struct as_one_base | |
327 | : std::unary_function<Arg, typename remove_const<Arg>::type> | |
328 | { | |
329 | typename remove_const<Arg>::type operator ()(Arg &) const | |
330 | { | |
331 | return numeric::one<typename remove_const<Arg>::type>::value; | |
332 | } | |
333 | }; | |
334 | ||
335 | template<typename To, typename From, typename ToTag, typename FromTag> | |
336 | struct promote | |
337 | : promote_base<To, From, void> | |
338 | {}; | |
339 | ||
340 | template<typename Left, typename Right, typename LeftTag, typename RightTag> | |
341 | struct min_assign | |
342 | : min_assign_base<Left, Right, void> | |
343 | {}; | |
344 | ||
345 | template<typename Left, typename Right, typename LeftTag, typename RightTag> | |
346 | struct max_assign | |
347 | : max_assign_base<Left, Right, void> | |
348 | {}; | |
349 | ||
350 | template<typename Left, typename Right, typename LeftTag, typename RightTag> | |
351 | struct fdiv | |
352 | : fdiv_base<Left, Right, void> | |
353 | {}; | |
354 | ||
355 | /// INTERNAL ONLY | |
356 | /// For back-compat only. Use fdiv. | |
357 | template<typename Left, typename Right, typename LeftTag, typename RightTag> | |
358 | struct average | |
359 | : fdiv<Left, Right, LeftTag, RightTag> | |
360 | {}; | |
361 | ||
362 | template<typename Arg, typename Tag> | |
363 | struct as_min | |
364 | : as_min_base<Arg, void> | |
365 | {}; | |
366 | ||
367 | template<typename Arg, typename Tag> | |
368 | struct as_max | |
369 | : as_max_base<Arg, void> | |
370 | {}; | |
371 | ||
372 | template<typename Arg, typename Tag> | |
373 | struct as_zero | |
374 | : as_zero_base<Arg, void> | |
375 | {}; | |
376 | ||
377 | template<typename Arg, typename Tag> | |
378 | struct as_one | |
379 | : as_one_base<Arg, void> | |
380 | {}; | |
381 | } | |
382 | ||
383 | namespace op | |
384 | { | |
385 | template<typename To> | |
386 | struct promote | |
387 | : boost::detail::function1<functional::promote<To, _, typename functional::tag<To>::type, functional::tag<_> > > | |
388 | {}; | |
389 | ||
390 | struct min_assign | |
391 | : boost::detail::function2<functional::min_assign<_1, _2, functional::tag<_1>, functional::tag<_2> > > | |
392 | {}; | |
393 | ||
394 | struct max_assign | |
395 | : boost::detail::function2<functional::max_assign<_1, _2, functional::tag<_1>, functional::tag<_2> > > | |
396 | {}; | |
397 | ||
398 | struct fdiv | |
399 | : boost::detail::function2<functional::fdiv<_1, _2, functional::tag<_1>, functional::tag<_2> > > | |
400 | {}; | |
401 | ||
402 | /// INTERNAL ONLY | |
403 | struct average | |
404 | : boost::detail::function2<functional::fdiv<_1, _2, functional::tag<_1>, functional::tag<_2> > > | |
405 | {}; | |
406 | ||
407 | struct as_min | |
408 | : boost::detail::function1<functional::as_min<_, functional::tag<_> > > | |
409 | {}; | |
410 | ||
411 | struct as_max | |
412 | : boost::detail::function1<functional::as_max<_, functional::tag<_> > > | |
413 | {}; | |
414 | ||
415 | struct as_zero | |
416 | : boost::detail::function1<functional::as_zero<_, functional::tag<_> > > | |
417 | {}; | |
418 | ||
419 | struct as_one | |
420 | : boost::detail::function1<functional::as_one<_, functional::tag<_> > > | |
421 | {}; | |
422 | } | |
423 | ||
424 | namespace | |
425 | { | |
426 | op::min_assign const &min_assign = boost::detail::pod_singleton<op::min_assign>::instance; | |
427 | op::max_assign const &max_assign = boost::detail::pod_singleton<op::max_assign>::instance; | |
428 | op::fdiv const &fdiv = boost::detail::pod_singleton<op::fdiv>::instance; | |
429 | op::fdiv const &average = boost::detail::pod_singleton<op::fdiv>::instance; ///< INTERNAL ONLY | |
430 | op::as_min const &as_min = boost::detail::pod_singleton<op::as_min>::instance; | |
431 | op::as_max const &as_max = boost::detail::pod_singleton<op::as_max>::instance; | |
432 | op::as_zero const &as_zero = boost::detail::pod_singleton<op::as_zero>::instance; | |
433 | op::as_one const &as_one = boost::detail::pod_singleton<op::as_one>::instance; | |
434 | ||
435 | BOOST_ACCUMULATORS_IGNORE_GLOBAL(min_assign) | |
436 | BOOST_ACCUMULATORS_IGNORE_GLOBAL(max_assign) | |
437 | BOOST_ACCUMULATORS_IGNORE_GLOBAL(fdiv) | |
438 | BOOST_ACCUMULATORS_IGNORE_GLOBAL(average) | |
439 | BOOST_ACCUMULATORS_IGNORE_GLOBAL(as_min) | |
440 | BOOST_ACCUMULATORS_IGNORE_GLOBAL(as_max) | |
441 | BOOST_ACCUMULATORS_IGNORE_GLOBAL(as_zero) | |
442 | BOOST_ACCUMULATORS_IGNORE_GLOBAL(as_one) | |
443 | } | |
444 | ||
445 | /////////////////////////////////////////////////////////////////////////////// | |
446 | // promote | |
447 | template<typename To, typename From> | |
448 | typename lazy_disable_if<is_const<From>, mpl::if_<is_same<To, From>, To &, To> >::type | |
449 | promote(From &from) | |
450 | { | |
451 | return functional::promote<To, From>()(from); | |
452 | } | |
453 | ||
454 | template<typename To, typename From> | |
455 | typename mpl::if_<is_same<To const, From const>, To const &, To const>::type | |
456 | promote(From const &from) | |
457 | { | |
458 | return functional::promote<To const, From const>()(from); | |
459 | } | |
460 | ||
461 | template<typename T> | |
462 | struct default_ | |
463 | { | |
464 | typedef default_ type; | |
465 | typedef T value_type; | |
466 | static T const value; | |
467 | ||
468 | operator T const & () const | |
469 | { | |
470 | return default_::value; | |
471 | } | |
472 | }; | |
473 | ||
474 | template<typename T> | |
475 | T const default_<T>::value = T(); | |
476 | ||
477 | template<typename T> | |
478 | struct one | |
479 | { | |
480 | typedef one type; | |
481 | typedef T value_type; | |
482 | static T const value; | |
483 | ||
484 | operator T const & () const | |
485 | { | |
486 | return one::value; | |
487 | } | |
488 | }; | |
489 | ||
490 | template<typename T> | |
491 | T const one<T>::value = T(1); | |
492 | ||
493 | template<typename T> | |
494 | struct zero | |
495 | { | |
496 | typedef zero type; | |
497 | typedef T value_type; | |
498 | static T const value; | |
499 | ||
500 | operator T const & () const | |
501 | { | |
502 | return zero::value; | |
503 | } | |
504 | }; | |
505 | ||
506 | template<typename T> | |
507 | T const zero<T>::value = T(); | |
508 | ||
509 | template<typename T> | |
510 | struct one_or_default | |
511 | : mpl::if_<is_empty<T>, default_<T>, one<T> >::type | |
512 | {}; | |
513 | ||
514 | template<typename T> | |
515 | struct zero_or_default | |
516 | : mpl::if_<is_empty<T>, default_<T>, zero<T> >::type | |
517 | {}; | |
518 | ||
519 | }} // namespace boost::numeric | |
520 | ||
521 | #endif |