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 | { \ |
103 | typedef typename remove_const<Arg>::type argument_type; \ |
104 | typedef typename result_of_ ## Name<Arg>::type result_type; \ |
105 | typename result_of_ ## Name<Arg>::type operator ()(Arg &arg) const \ |
106 | { \ |
107 | return Op arg; \ |
108 | } \ |
109 | }; \ |
110 | template<typename Arg, typename ArgTag> \ |
111 | struct Name \ |
112 | : Name ## _base<Arg, void> \ |
113 | {}; \ |
114 | } \ |
115 | namespace op \ |
116 | { \ |
117 | struct Name \ |
118 | : boost::detail::function1<functional::Name<_, functional::tag<_> > > \ |
119 | {}; \ |
120 | } \ |
121 | namespace \ |
122 | { \ |
123 | op::Name const &Name = boost::detail::pod_singleton<op::Name>::instance; \ |
124 | } \ |
125 | /**/ |
126 | |
127 | /// INTERNAL ONLY |
128 | /// |
129 | #define BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(Name, Op, RetType) \ |
130 | namespace functional \ |
131 | { \ |
132 | template<typename Left, typename Right, typename EnableIf> \ |
133 | struct result_of_ ## Name \ |
134 | { \ |
135 | RetType(Left, Op, Right) \ |
136 | }; \ |
137 | template<typename Left, typename Right, typename EnableIf> \ |
138 | struct Name ## _base \ |
139 | { \ |
140 | typedef typename remove_const<Left>::type first_argument_type; \ |
141 | typedef typename remove_const<Right>::type second_argument_type; \ |
142 | typedef typename result_of_ ## Name<Left, Right>::type result_type; \ |
143 | typename result_of_ ## Name<Left, Right>::type \ |
144 | operator ()(Left &left, Right &right) const \ |
145 | { \ |
146 | return left Op right; \ |
147 | } \ |
148 | }; \ |
149 | template<typename Left, typename Right, typename LeftTag, typename RightTag> \ |
150 | struct Name \ |
151 | : Name ## _base<Left, Right, void> \ |
152 | {}; \ |
153 | } \ |
154 | namespace op \ |
155 | { \ |
156 | struct Name \ |
157 | : boost::detail::function2< \ |
158 | functional::Name<_1, _2, functional::tag<_1>, functional::tag<_2> > \ |
159 | > \ |
160 | {}; \ |
161 | } \ |
162 | namespace \ |
163 | { \ |
164 | op::Name const &Name = boost::detail::pod_singleton<op::Name>::instance; \ |
165 | } \ |
166 | BOOST_ACCUMULATORS_IGNORE_GLOBAL(Name) \ |
167 | /**/ |
168 | |
169 | /// INTERNAL ONLY |
170 | /// |
171 | #define BOOST_NUMERIC_FUNCTIONAL_DEDUCED(Left, Op, Right) \ |
172 | BOOST_TYPEOF_NESTED_TYPEDEF_TPL( \ |
173 | nested \ |
174 | , boost::numeric::functional::detail::lvalue_of<Left>() Op \ |
175 | boost::numeric::functional::detail::lvalue_of<Right>() \ |
176 | ) \ |
177 | typedef typename nested::type type; \ |
178 | /**/ |
179 | |
180 | /// INTERNAL ONLY |
181 | /// |
182 | #define BOOST_NUMERIC_FUNCTIONAL_LEFT(Left, Op, Right) \ |
183 | typedef Left &type; \ |
184 | /**/ |
185 | |
186 | BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(plus, +, BOOST_NUMERIC_FUNCTIONAL_DEDUCED) |
187 | BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(minus, -, BOOST_NUMERIC_FUNCTIONAL_DEDUCED) |
188 | BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(multiplies, *, BOOST_NUMERIC_FUNCTIONAL_DEDUCED) |
189 | BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(divides, /, BOOST_NUMERIC_FUNCTIONAL_DEDUCED) |
190 | BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(modulus, %, BOOST_NUMERIC_FUNCTIONAL_DEDUCED) |
191 | BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(greater, >, BOOST_NUMERIC_FUNCTIONAL_DEDUCED) |
192 | BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(greater_equal, >=, BOOST_NUMERIC_FUNCTIONAL_DEDUCED) |
193 | BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(less, <, BOOST_NUMERIC_FUNCTIONAL_DEDUCED) |
194 | BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(less_equal, <=, BOOST_NUMERIC_FUNCTIONAL_DEDUCED) |
195 | BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(equal_to, ==, BOOST_NUMERIC_FUNCTIONAL_DEDUCED) |
196 | BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(not_equal_to, !=, BOOST_NUMERIC_FUNCTIONAL_DEDUCED) |
197 | |
198 | BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(assign, =, BOOST_NUMERIC_FUNCTIONAL_LEFT) |
199 | BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(plus_assign, +=, BOOST_NUMERIC_FUNCTIONAL_LEFT) |
200 | BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(minus_assign, -=, BOOST_NUMERIC_FUNCTIONAL_LEFT) |
201 | BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(multiplies_assign, *=, BOOST_NUMERIC_FUNCTIONAL_LEFT) |
202 | BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(divides_assign, /=, BOOST_NUMERIC_FUNCTIONAL_LEFT) |
203 | BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(modulus_assign, %=, BOOST_NUMERIC_FUNCTIONAL_LEFT) |
204 | |
205 | BOOST_NUMERIC_FUNCTIONAL_DEFINE_UNARY_OP(unary_plus, +) |
206 | BOOST_NUMERIC_FUNCTIONAL_DEFINE_UNARY_OP(unary_minus, -) |
207 | BOOST_NUMERIC_FUNCTIONAL_DEFINE_UNARY_OP(complement, ~) |
208 | BOOST_NUMERIC_FUNCTIONAL_DEFINE_UNARY_OP(logical_not, !) |
209 | |
210 | #undef BOOST_NUMERIC_FUNCTIONAL_LEFT |
211 | #undef BOOST_NUMERIC_FUNCTIONAL_DEDUCED |
212 | #undef BOOST_NUMERIC_FUNCTIONAL_DEFINE_UNARY_OP |
213 | #undef BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP |
214 | |
215 | namespace functional |
216 | { |
217 | template<typename Left, typename Right, typename EnableIf> |
218 | struct min_assign_base |
219 | { |
220 | typedef Left first_argument_type; |
221 | typedef Right second_argument_type; |
222 | typedef void result_type; |
223 | |
224 | void operator ()(Left &left, Right &right) const |
225 | { |
226 | if(numeric::less(right, left)) |
227 | { |
228 | left = right; |
229 | } |
230 | } |
231 | }; |
232 | |
233 | template<typename Left, typename Right, typename EnableIf> |
234 | struct max_assign_base |
235 | { |
236 | typedef Left first_argument_type; |
237 | typedef Right second_argument_type; |
238 | typedef void result_type; |
239 | |
240 | void operator ()(Left &left, Right &right) const |
241 | { |
242 | if(numeric::greater(right, left)) |
243 | { |
244 | left = right; |
245 | } |
246 | } |
247 | }; |
248 | |
249 | template<typename Left, typename Right, typename EnableIf> |
250 | struct fdiv_base |
251 | : functional::divides<Left, Right> |
252 | {}; |
253 | |
254 | // partial specialization that promotes the arguments to double for |
255 | // integral division. |
256 | template<typename Left, typename Right> |
257 | struct fdiv_base<Left, Right, typename enable_if<are_integral<Left, Right> >::type> |
258 | : functional::divides<double const, double const> |
259 | {}; |
260 | |
261 | template<typename To, typename From, typename EnableIf> |
262 | struct promote_base |
263 | { |
264 | typedef From argument_type; |
265 | typedef To result_type; |
266 | |
267 | To operator ()(From &from) const |
268 | { |
269 | return from; |
270 | } |
271 | }; |
272 | |
273 | template<typename ToFrom> |
274 | struct promote_base<ToFrom, ToFrom, void> |
275 | { |
276 | typedef ToFrom argument_type; |
277 | typedef ToFrom result_type; |
278 | |
279 | ToFrom &operator ()(ToFrom &tofrom) |
280 | { |
281 | return tofrom; |
282 | } |
283 | }; |
284 | |
285 | template<typename Arg, typename EnableIf> |
286 | struct as_min_base |
287 | { |
288 | BOOST_STATIC_ASSERT(std::numeric_limits<typename remove_const<Arg>::type>::is_specialized); |
289 | |
290 | typedef Arg argument_type; |
291 | typedef typename remove_const<Arg>::type result_type; |
292 | |
293 | typename remove_const<Arg>::type operator ()(Arg &) const |
294 | { |
295 | return (std::numeric_limits<typename remove_const<Arg>::type>::min)(); |
296 | } |
297 | }; |
298 | |
299 | template<typename Arg> |
300 | struct as_min_base<Arg, typename enable_if<is_floating_point<Arg> >::type> |
301 | { |
302 | BOOST_STATIC_ASSERT(std::numeric_limits<typename remove_const<Arg>::type>::is_specialized); |
303 | |
304 | typedef Arg argument_type; |
305 | typedef typename remove_const<Arg>::type result_type; |
306 | |
307 | typename remove_const<Arg>::type operator ()(Arg &) const |
308 | { |
309 | return -(std::numeric_limits<typename remove_const<Arg>::type>::max)(); |
310 | } |
311 | }; |
312 | |
313 | template<typename Arg, typename EnableIf> |
314 | struct as_max_base |
315 | { |
316 | BOOST_STATIC_ASSERT(std::numeric_limits<typename remove_const<Arg>::type>::is_specialized); |
317 | |
318 | typedef Arg argument_type; |
319 | typedef typename remove_const<Arg>::type result_type; |
320 | |
321 | typename remove_const<Arg>::type operator ()(Arg &) const |
322 | { |
323 | return (std::numeric_limits<typename remove_const<Arg>::type>::max)(); |
324 | } |
325 | }; |
326 | |
327 | template<typename Arg, typename EnableIf> |
328 | struct as_zero_base |
329 | { |
330 | typedef Arg argument_type; |
331 | typedef typename remove_const<Arg>::type result_type; |
332 | |
333 | typename remove_const<Arg>::type operator ()(Arg &) const |
334 | { |
335 | return numeric::zero<typename remove_const<Arg>::type>::value; |
336 | } |
337 | }; |
338 | |
339 | template<typename Arg, typename EnableIf> |
340 | struct as_one_base |
341 | { |
342 | typedef Arg argument_type; |
343 | typedef typename remove_const<Arg>::type result_type; |
344 | |
345 | typename remove_const<Arg>::type operator ()(Arg &) const |
346 | { |
347 | return numeric::one<typename remove_const<Arg>::type>::value; |
348 | } |
349 | }; |
350 | |
351 | template<typename To, typename From, typename ToTag, typename FromTag> |
352 | struct promote |
353 | : promote_base<To, From, void> |
354 | {}; |
355 | |
356 | template<typename Left, typename Right, typename LeftTag, typename RightTag> |
357 | struct min_assign |
358 | : min_assign_base<Left, Right, void> |
359 | {}; |
360 | |
361 | template<typename Left, typename Right, typename LeftTag, typename RightTag> |
362 | struct max_assign |
363 | : max_assign_base<Left, Right, void> |
364 | {}; |
365 | |
366 | template<typename Left, typename Right, typename LeftTag, typename RightTag> |
367 | struct fdiv |
368 | : fdiv_base<Left, Right, void> |
369 | {}; |
370 | |
371 | /// INTERNAL ONLY |
372 | /// For back-compat only. Use fdiv. |
373 | template<typename Left, typename Right, typename LeftTag, typename RightTag> |
374 | struct average |
375 | : fdiv<Left, Right, LeftTag, RightTag> |
376 | {}; |
377 | |
378 | template<typename Arg, typename Tag> |
379 | struct as_min |
380 | : as_min_base<Arg, void> |
381 | {}; |
382 | |
383 | template<typename Arg, typename Tag> |
384 | struct as_max |
385 | : as_max_base<Arg, void> |
386 | {}; |
387 | |
388 | template<typename Arg, typename Tag> |
389 | struct as_zero |
390 | : as_zero_base<Arg, void> |
391 | {}; |
392 | |
393 | template<typename Arg, typename Tag> |
394 | struct as_one |
395 | : as_one_base<Arg, void> |
396 | {}; |
397 | } |
398 | |
399 | namespace op |
400 | { |
401 | template<typename To> |
402 | struct promote |
403 | : boost::detail::function1<functional::promote<To, _, typename functional::tag<To>::type, functional::tag<_> > > |
404 | {}; |
405 | |
406 | struct min_assign |
407 | : boost::detail::function2<functional::min_assign<_1, _2, functional::tag<_1>, functional::tag<_2> > > |
408 | {}; |
409 | |
410 | struct max_assign |
411 | : boost::detail::function2<functional::max_assign<_1, _2, functional::tag<_1>, functional::tag<_2> > > |
412 | {}; |
413 | |
414 | struct fdiv |
415 | : boost::detail::function2<functional::fdiv<_1, _2, functional::tag<_1>, functional::tag<_2> > > |
416 | {}; |
417 | |
418 | /// INTERNAL ONLY |
419 | struct average |
420 | : boost::detail::function2<functional::fdiv<_1, _2, functional::tag<_1>, functional::tag<_2> > > |
421 | {}; |
422 | |
423 | struct as_min |
424 | : boost::detail::function1<functional::as_min<_, functional::tag<_> > > |
425 | {}; |
426 | |
427 | struct as_max |
428 | : boost::detail::function1<functional::as_max<_, functional::tag<_> > > |
429 | {}; |
430 | |
431 | struct as_zero |
432 | : boost::detail::function1<functional::as_zero<_, functional::tag<_> > > |
433 | {}; |
434 | |
435 | struct as_one |
436 | : boost::detail::function1<functional::as_one<_, functional::tag<_> > > |
437 | {}; |
438 | } |
439 | |
440 | namespace |
441 | { |
442 | op::min_assign const &min_assign = boost::detail::pod_singleton<op::min_assign>::instance; |
443 | op::max_assign const &max_assign = boost::detail::pod_singleton<op::max_assign>::instance; |
444 | op::fdiv const &fdiv = boost::detail::pod_singleton<op::fdiv>::instance; |
445 | op::fdiv const &average = boost::detail::pod_singleton<op::fdiv>::instance; ///< INTERNAL ONLY |
446 | op::as_min const &as_min = boost::detail::pod_singleton<op::as_min>::instance; |
447 | op::as_max const &as_max = boost::detail::pod_singleton<op::as_max>::instance; |
448 | op::as_zero const &as_zero = boost::detail::pod_singleton<op::as_zero>::instance; |
449 | op::as_one const &as_one = boost::detail::pod_singleton<op::as_one>::instance; |
450 | |
451 | BOOST_ACCUMULATORS_IGNORE_GLOBAL(min_assign) |
452 | BOOST_ACCUMULATORS_IGNORE_GLOBAL(max_assign) |
453 | BOOST_ACCUMULATORS_IGNORE_GLOBAL(fdiv) |
454 | BOOST_ACCUMULATORS_IGNORE_GLOBAL(average) |
455 | BOOST_ACCUMULATORS_IGNORE_GLOBAL(as_min) |
456 | BOOST_ACCUMULATORS_IGNORE_GLOBAL(as_max) |
457 | BOOST_ACCUMULATORS_IGNORE_GLOBAL(as_zero) |
458 | BOOST_ACCUMULATORS_IGNORE_GLOBAL(as_one) |
459 | } |
460 | |
461 | /////////////////////////////////////////////////////////////////////////////// |
462 | // promote |
463 | template<typename To, typename From> |
464 | typename lazy_disable_if<is_const<From>, mpl::if_<is_same<To, From>, To &, To> >::type |
465 | promote(From &from) |
466 | { |
467 | return functional::promote<To, From>()(from); |
468 | } |
469 | |
470 | template<typename To, typename From> |
471 | typename mpl::if_<is_same<To const, From const>, To const &, To const>::type |
472 | promote(From const &from) |
473 | { |
474 | return functional::promote<To const, From const>()(from); |
475 | } |
476 | |
477 | template<typename T> |
478 | struct default_ |
479 | { |
480 | typedef default_ type; |
481 | typedef T value_type; |
482 | static T const value; |
483 | |
484 | operator T const & () const |
485 | { |
486 | return default_::value; |
487 | } |
488 | }; |
489 | |
490 | template<typename T> |
491 | T const default_<T>::value = T(); |
492 | |
493 | template<typename T> |
494 | struct one |
495 | { |
496 | typedef one type; |
497 | typedef T value_type; |
498 | static T const value; |
499 | |
500 | operator T const & () const |
501 | { |
502 | return one::value; |
503 | } |
504 | }; |
505 | |
506 | template<typename T> |
507 | T const one<T>::value = T(1); |
508 | |
509 | template<typename T> |
510 | struct zero |
511 | { |
512 | typedef zero type; |
513 | typedef T value_type; |
514 | static T const value; |
515 | |
516 | operator T const & () const |
517 | { |
518 | return zero::value; |
519 | } |
520 | }; |
521 | |
522 | template<typename T> |
523 | T const zero<T>::value = T(); |
524 | |
525 | template<typename T> |
526 | struct one_or_default |
527 | : mpl::if_<is_empty<T>, default_<T>, one<T> >::type |
528 | {}; |
529 | |
530 | template<typename T> |
531 | struct zero_or_default |
532 | : mpl::if_<is_empty<T>, default_<T>, zero<T> >::type |
533 | {}; |
534 | |
535 | }} // namespace boost::numeric |
536 | |
537 | #endif |
538 | |