You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
497 lines
21 KiB
497 lines
21 KiB
/////////////////////////////////////////////////////////////////////////////// |
|
/// \file functional.hpp |
|
/// |
|
// Copyright 2005 Eric Niebler. Distributed under the Boost |
|
// Software License, Version 1.0. (See accompanying file |
|
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
|
|
|
#ifndef BOOST_NUMERIC_FUNCTIONAL_HPP_EAN_08_12_2005 |
|
#define BOOST_NUMERIC_FUNCTIONAL_HPP_EAN_08_12_2005 |
|
|
|
#include <limits> |
|
#include <functional> |
|
#include <boost/static_assert.hpp> |
|
#include <boost/mpl/if.hpp> |
|
#include <boost/mpl/and.hpp> |
|
#include <boost/type_traits/remove_const.hpp> |
|
#include <boost/type_traits/add_reference.hpp> |
|
#include <boost/type_traits/is_empty.hpp> |
|
#include <boost/type_traits/is_integral.hpp> |
|
#include <boost/type_traits/is_floating_point.hpp> |
|
#include <boost/utility/enable_if.hpp> |
|
#include <boost/typeof/typeof.hpp> |
|
#include <boost/accumulators/numeric/functional_fwd.hpp> |
|
#include <boost/accumulators/numeric/detail/function1.hpp> |
|
#include <boost/accumulators/numeric/detail/function2.hpp> |
|
#include <boost/accumulators/numeric/detail/pod_singleton.hpp> |
|
|
|
#ifdef BOOST_NUMERIC_FUNCTIONAL_STD_VECTOR_SUPPORT |
|
# include <boost/accumulators/numeric/functional/vector.hpp> |
|
#endif |
|
|
|
#ifdef BOOST_NUMERIC_FUNCTIONAL_STD_VALARRAY_SUPPORT |
|
# include <boost/accumulators/numeric/functional/valarray.hpp> |
|
#endif |
|
|
|
#ifdef BOOST_NUMERIC_FUNCTIONAL_STD_COMPLEX_SUPPORT |
|
# include <boost/accumulators/numeric/functional/complex.hpp> |
|
#endif |
|
|
|
/// INTERNAL ONLY |
|
/// |
|
#define BOOST_NUMERIC_FUNCTIONAL_HPP_INCLUDED |
|
|
|
#ifdef BOOST_NUMERIC_FUNCTIONAL_DOXYGEN_INVOKED |
|
// Hack to make Doxygen show the inheritance relationships |
|
/// INTERNAL ONLY |
|
/// |
|
namespace std |
|
{ |
|
/// INTERNAL ONLY |
|
/// |
|
template<class Arg, class Ret> struct unary_function {}; |
|
/// INTERNAL ONLY |
|
/// |
|
template<class Left, class Right, class Ret> struct binary_function {}; |
|
} |
|
#endif |
|
|
|
namespace boost { namespace numeric |
|
{ |
|
namespace functional |
|
{ |
|
/// INTERNAL ONLY |
|
/// |
|
template<typename A0, typename A1> |
|
struct are_integral |
|
: mpl::and_<is_integral<A0>, is_integral<A1> > |
|
{}; |
|
|
|
template<typename Left, typename Right> |
|
struct left_ref |
|
{ |
|
typedef Left &type; |
|
}; |
|
|
|
namespace detail |
|
{ |
|
template<typename T> |
|
T &lvalue_of(); |
|
} |
|
} |
|
|
|
// TODO: handle complex weight, valarray, MTL vectors |
|
|
|
/// INTERNAL ONLY |
|
/// |
|
#define BOOST_NUMERIC_FUNCTIONAL_DEFINE_UNARY_OP(Name, Op) \ |
|
namespace functional \ |
|
{ \ |
|
template<typename Arg> \ |
|
struct result_of_ ## Name \ |
|
{ \ |
|
BOOST_TYPEOF_NESTED_TYPEDEF_TPL( \ |
|
nested \ |
|
, Op boost::numeric::functional::detail::lvalue_of<Arg>() \ |
|
) \ |
|
typedef typename nested::type type; \ |
|
}; \ |
|
template<typename Arg, typename EnableIf> \ |
|
struct Name ## _base \ |
|
: std::unary_function< \ |
|
typename remove_const<Arg>::type \ |
|
, typename result_of_ ## Name<Arg>::type \ |
|
> \ |
|
{ \ |
|
typename result_of_ ## Name<Arg>::type operator ()(Arg &arg) const \ |
|
{ \ |
|
return Op arg; \ |
|
} \ |
|
}; \ |
|
template<typename Arg, typename ArgTag> \ |
|
struct Name \ |
|
: Name ## _base<Arg, void> \ |
|
{}; \ |
|
} \ |
|
namespace op \ |
|
{ \ |
|
struct Name \ |
|
: boost::detail::function1<functional::Name<_, functional::tag<_> > > \ |
|
{}; \ |
|
} \ |
|
namespace \ |
|
{ \ |
|
op::Name const &Name = boost::detail::pod_singleton<op::Name>::instance; \ |
|
} \ |
|
/**/ |
|
|
|
/// INTERNAL ONLY |
|
/// |
|
#define BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(Name, Op, RetType) \ |
|
namespace functional \ |
|
{ \ |
|
template<typename Left, typename Right, typename EnableIf> \ |
|
struct result_of_ ## Name \ |
|
{ \ |
|
RetType(Left, Op, Right) \ |
|
}; \ |
|
template<typename Left, typename Right, typename EnableIf> \ |
|
struct Name ## _base \ |
|
: std::binary_function< \ |
|
typename remove_const<Left>::type \ |
|
, typename remove_const<Right>::type \ |
|
, typename result_of_ ## Name<Left, Right>::type \ |
|
> \ |
|
{ \ |
|
typename result_of_ ## Name<Left, Right>::type \ |
|
operator ()(Left &left, Right &right) const \ |
|
{ \ |
|
return left Op right; \ |
|
} \ |
|
}; \ |
|
template<typename Left, typename Right, typename LeftTag, typename RightTag> \ |
|
struct Name \ |
|
: Name ## _base<Left, Right, void> \ |
|
{}; \ |
|
} \ |
|
namespace op \ |
|
{ \ |
|
struct Name \ |
|
: boost::detail::function2< \ |
|
functional::Name<_1, _2, functional::tag<_1>, functional::tag<_2> > \ |
|
> \ |
|
{}; \ |
|
} \ |
|
namespace \ |
|
{ \ |
|
op::Name const &Name = boost::detail::pod_singleton<op::Name>::instance; \ |
|
} \ |
|
/**/ |
|
|
|
/// INTERNAL ONLY |
|
/// |
|
#define BOOST_NUMERIC_FUNCTIONAL_DEDUCED(Left, Op, Right) \ |
|
BOOST_TYPEOF_NESTED_TYPEDEF_TPL( \ |
|
nested \ |
|
, boost::numeric::functional::detail::lvalue_of<Left>() Op \ |
|
boost::numeric::functional::detail::lvalue_of<Right>() \ |
|
) \ |
|
typedef typename nested::type type; \ |
|
/**/ |
|
|
|
/// INTERNAL ONLY |
|
/// |
|
#define BOOST_NUMERIC_FUNCTIONAL_LEFT(Left, Op, Right) \ |
|
typedef Left &type; \ |
|
/**/ |
|
|
|
BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(plus, +, BOOST_NUMERIC_FUNCTIONAL_DEDUCED) |
|
BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(minus, -, BOOST_NUMERIC_FUNCTIONAL_DEDUCED) |
|
BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(multiplies, *, BOOST_NUMERIC_FUNCTIONAL_DEDUCED) |
|
BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(divides, /, BOOST_NUMERIC_FUNCTIONAL_DEDUCED) |
|
BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(modulus, %, BOOST_NUMERIC_FUNCTIONAL_DEDUCED) |
|
BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(greater, >, BOOST_NUMERIC_FUNCTIONAL_DEDUCED) |
|
BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(greater_equal, >=, BOOST_NUMERIC_FUNCTIONAL_DEDUCED) |
|
BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(less, <, BOOST_NUMERIC_FUNCTIONAL_DEDUCED) |
|
BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(less_equal, <=, BOOST_NUMERIC_FUNCTIONAL_DEDUCED) |
|
BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(equal_to, ==, BOOST_NUMERIC_FUNCTIONAL_DEDUCED) |
|
BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(not_equal_to, !=, BOOST_NUMERIC_FUNCTIONAL_DEDUCED) |
|
|
|
BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(assign, =, BOOST_NUMERIC_FUNCTIONAL_LEFT) |
|
BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(plus_assign, +=, BOOST_NUMERIC_FUNCTIONAL_LEFT) |
|
BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(minus_assign, -=, BOOST_NUMERIC_FUNCTIONAL_LEFT) |
|
BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(multiplies_assign, *=, BOOST_NUMERIC_FUNCTIONAL_LEFT) |
|
BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(divides_assign, /=, BOOST_NUMERIC_FUNCTIONAL_LEFT) |
|
BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(modulus_assign, %=, BOOST_NUMERIC_FUNCTIONAL_LEFT) |
|
|
|
BOOST_NUMERIC_FUNCTIONAL_DEFINE_UNARY_OP(unary_plus, +) |
|
BOOST_NUMERIC_FUNCTIONAL_DEFINE_UNARY_OP(unary_minus, -) |
|
BOOST_NUMERIC_FUNCTIONAL_DEFINE_UNARY_OP(complement, ~) |
|
BOOST_NUMERIC_FUNCTIONAL_DEFINE_UNARY_OP(logical_not, !) |
|
|
|
#undef BOOST_NUMERIC_FUNCTIONAL_LEFT |
|
#undef BOOST_NUMERIC_FUNCTIONAL_DEDUCED |
|
#undef BOOST_NUMERIC_FUNCTIONAL_DEFINE_UNARY_OP |
|
#undef BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP |
|
|
|
namespace functional |
|
{ |
|
template<typename Left, typename Right, typename EnableIf> |
|
struct min_assign_base |
|
: std::binary_function<Left, Right, void> |
|
{ |
|
void operator ()(Left &left, Right &right) const |
|
{ |
|
if(numeric::less(right, left)) |
|
{ |
|
left = right; |
|
} |
|
} |
|
}; |
|
|
|
template<typename Left, typename Right, typename EnableIf> |
|
struct max_assign_base |
|
: std::binary_function<Left, Right, void> |
|
{ |
|
void operator ()(Left &left, Right &right) const |
|
{ |
|
if(numeric::greater(right, left)) |
|
{ |
|
left = right; |
|
} |
|
} |
|
}; |
|
|
|
template<typename Left, typename Right, typename EnableIf> |
|
struct average_base |
|
: functional::divides<Left, Right> |
|
{}; |
|
|
|
// partial specialization that promotes the arguments to double for |
|
// integral division. |
|
template<typename Left, typename Right> |
|
struct average_base<Left, Right, typename enable_if<are_integral<Left, Right> >::type> |
|
: functional::divides<double const, double const> |
|
{}; |
|
|
|
template<typename To, typename From, typename EnableIf> |
|
struct promote_base |
|
: std::unary_function<From, To> |
|
{ |
|
To operator ()(From &from) const |
|
{ |
|
return from; |
|
} |
|
}; |
|
|
|
template<typename ToFrom> |
|
struct promote_base<ToFrom, ToFrom, void> |
|
: std::unary_function<ToFrom, ToFrom> |
|
{ |
|
ToFrom &operator ()(ToFrom &tofrom) |
|
{ |
|
return tofrom; |
|
} |
|
}; |
|
|
|
template<typename Arg, typename EnableIf> |
|
struct as_min_base |
|
: std::unary_function<Arg, typename remove_const<Arg>::type> |
|
{ |
|
BOOST_STATIC_ASSERT(std::numeric_limits<typename remove_const<Arg>::type>::is_specialized); |
|
|
|
typename remove_const<Arg>::type operator ()(Arg &) const |
|
{ |
|
return (std::numeric_limits<typename remove_const<Arg>::type>::min)(); |
|
} |
|
}; |
|
|
|
template<typename Arg> |
|
struct as_min_base<Arg, typename enable_if<is_floating_point<Arg> >::type> |
|
: std::unary_function<Arg, typename remove_const<Arg>::type> |
|
{ |
|
BOOST_STATIC_ASSERT(std::numeric_limits<typename remove_const<Arg>::type>::is_specialized); |
|
|
|
typename remove_const<Arg>::type operator ()(Arg &) const |
|
{ |
|
return -(std::numeric_limits<typename remove_const<Arg>::type>::max)(); |
|
} |
|
}; |
|
|
|
template<typename Arg, typename EnableIf> |
|
struct as_max_base |
|
: std::unary_function<Arg, typename remove_const<Arg>::type> |
|
{ |
|
BOOST_STATIC_ASSERT(std::numeric_limits<typename remove_const<Arg>::type>::is_specialized); |
|
|
|
typename remove_const<Arg>::type operator ()(Arg &) const |
|
{ |
|
return (std::numeric_limits<typename remove_const<Arg>::type>::max)(); |
|
} |
|
}; |
|
|
|
template<typename Arg, typename EnableIf> |
|
struct as_zero_base |
|
: std::unary_function<Arg, typename remove_const<Arg>::type> |
|
{ |
|
typename remove_const<Arg>::type operator ()(Arg &) const |
|
{ |
|
return numeric::zero<typename remove_const<Arg>::type>::value; |
|
} |
|
}; |
|
|
|
template<typename Arg, typename EnableIf> |
|
struct as_one_base |
|
: std::unary_function<Arg, typename remove_const<Arg>::type> |
|
{ |
|
typename remove_const<Arg>::type operator ()(Arg &) const |
|
{ |
|
return numeric::one<typename remove_const<Arg>::type>::value; |
|
} |
|
}; |
|
|
|
template<typename To, typename From, typename ToTag, typename FromTag> |
|
struct promote |
|
: promote_base<To, From, void> |
|
{}; |
|
|
|
template<typename Left, typename Right, typename LeftTag, typename RightTag> |
|
struct min_assign |
|
: min_assign_base<Left, Right, void> |
|
{}; |
|
|
|
template<typename Left, typename Right, typename LeftTag, typename RightTag> |
|
struct max_assign |
|
: max_assign_base<Left, Right, void> |
|
{}; |
|
|
|
template<typename Left, typename Right, typename LeftTag, typename RightTag> |
|
struct average |
|
: average_base<Left, Right, void> |
|
{}; |
|
|
|
template<typename Arg, typename Tag> |
|
struct as_min |
|
: as_min_base<Arg, void> |
|
{}; |
|
|
|
template<typename Arg, typename Tag> |
|
struct as_max |
|
: as_max_base<Arg, void> |
|
{}; |
|
|
|
template<typename Arg, typename Tag> |
|
struct as_zero |
|
: as_zero_base<Arg, void> |
|
{}; |
|
|
|
template<typename Arg, typename Tag> |
|
struct as_one |
|
: as_one_base<Arg, void> |
|
{}; |
|
} |
|
|
|
namespace op |
|
{ |
|
template<typename To> |
|
struct promote |
|
: boost::detail::function1<functional::promote<To, _, typename functional::tag<To>::type, functional::tag<_> > > |
|
{}; |
|
|
|
struct min_assign |
|
: boost::detail::function2<functional::min_assign<_1, _2, functional::tag<_1>, functional::tag<_2> > > |
|
{}; |
|
|
|
struct max_assign |
|
: boost::detail::function2<functional::max_assign<_1, _2, functional::tag<_1>, functional::tag<_2> > > |
|
{}; |
|
|
|
struct average |
|
: boost::detail::function2<functional::average<_1, _2, functional::tag<_1>, functional::tag<_2> > > |
|
{}; |
|
|
|
struct as_min |
|
: boost::detail::function1<functional::as_min<_, functional::tag<_> > > |
|
{}; |
|
|
|
struct as_max |
|
: boost::detail::function1<functional::as_max<_, functional::tag<_> > > |
|
{}; |
|
|
|
struct as_zero |
|
: boost::detail::function1<functional::as_zero<_, functional::tag<_> > > |
|
{}; |
|
|
|
struct as_one |
|
: boost::detail::function1<functional::as_one<_, functional::tag<_> > > |
|
{}; |
|
} |
|
|
|
namespace |
|
{ |
|
op::min_assign const &min_assign = boost::detail::pod_singleton<op::min_assign>::instance; |
|
op::max_assign const &max_assign = boost::detail::pod_singleton<op::max_assign>::instance; |
|
op::average const &average = boost::detail::pod_singleton<op::average>::instance; |
|
op::as_min const &as_min = boost::detail::pod_singleton<op::as_min>::instance; |
|
op::as_max const &as_max = boost::detail::pod_singleton<op::as_max>::instance; |
|
op::as_zero const &as_zero = boost::detail::pod_singleton<op::as_zero>::instance; |
|
op::as_one const &as_one = boost::detail::pod_singleton<op::as_one>::instance; |
|
} |
|
|
|
/////////////////////////////////////////////////////////////////////////////// |
|
// promote |
|
template<typename To, typename From> |
|
typename lazy_disable_if<is_const<From>, mpl::if_<is_same<To, From>, To &, To> >::type |
|
promote(From &from) |
|
{ |
|
return functional::promote<To, From>()(from); |
|
} |
|
|
|
template<typename To, typename From> |
|
typename mpl::if_<is_same<To const, From const>, To const &, To const>::type |
|
promote(From const &from) |
|
{ |
|
return functional::promote<To const, From const>()(from); |
|
} |
|
|
|
template<typename T> |
|
struct default_ |
|
{ |
|
typedef default_ type; |
|
typedef T value_type; |
|
static T const value; |
|
|
|
operator T const & () const |
|
{ |
|
return default_::value; |
|
} |
|
}; |
|
|
|
template<typename T> |
|
T const default_<T>::value = T(); |
|
|
|
template<typename T> |
|
struct one |
|
{ |
|
typedef one type; |
|
typedef T value_type; |
|
static T const value; |
|
|
|
operator T const & () const |
|
{ |
|
return one::value; |
|
} |
|
}; |
|
|
|
template<typename T> |
|
T const one<T>::value = T(1); |
|
|
|
template<typename T> |
|
struct zero |
|
{ |
|
typedef zero type; |
|
typedef T value_type; |
|
static T const value; |
|
|
|
operator T const & () const |
|
{ |
|
return zero::value; |
|
} |
|
}; |
|
|
|
template<typename T> |
|
T const zero<T>::value = T(); |
|
|
|
template<typename T> |
|
struct one_or_default |
|
: mpl::if_<is_empty<T>, default_<T>, one<T> >::type |
|
{}; |
|
|
|
template<typename T> |
|
struct zero_or_default |
|
: mpl::if_<is_empty<T>, default_<T>, zero<T> >::type |
|
{}; |
|
|
|
}} // namespace boost::numeric |
|
|
|
#endif
|
|
|