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 operator ()boost::numeric::functional::min_assign_base224 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 operator ()boost::numeric::functional::max_assign_base240 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 operator ()boost::numeric::functional::promote_base267 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 operator ()boost::numeric::functional::promote_base279 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 operator ()boost::numeric::functional::as_min_base293 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 operator ()boost::numeric::functional::as_min_base307 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 operator ()boost::numeric::functional::as_max_base321 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 operator ()boost::numeric::functional::as_zero_base333 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 operator ()boost::numeric::functional::as_one_base345 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 promote(From & from)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 promote(From const & from)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 operator T const&boost::numeric::default_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 operator T const&boost::numeric::one500 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 operator T const&boost::numeric::zero516 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