//  Copyright John Maddock 2007.



//  Use, modification and distribution are subject to 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)



/*

This header defines two traits classes, both in namespace boost::math::tools.



is_distribution<D>::value is true iff D has overloaded "cdf" and

"quantile" functions, plus member typedefs value_type and policy_type.  

It's not much of a definitive test frankly,

but if it looks like a distribution and quacks like a distribution

then it must be a distribution.



is_scaled_distribution<D>::value is true iff D is a distribution

as defined above, and has member functions "scale" and "location".



*/



#ifndef BOOST_STATS_IS_DISTRIBUTION_HPP

#define BOOST_STATS_IS_DISTRIBUTION_HPP



#include <boost/mpl/has_xxx.hpp>

// should be the last #include

#include <boost/type_traits/detail/bool_trait_def.hpp>



namespace boost{ namespace math{ namespace tools{



namespace detail{



BOOST_MPL_HAS_XXX_TRAIT_NAMED_DEF(has_value_type, value_type, true)

BOOST_MPL_HAS_XXX_TRAIT_NAMED_DEF(has_policy_type, policy_type, true)



template<class D>

char cdf(const D& ...);

template<class D>

char quantile(const D& ...);



template <class D>

struct has_cdf

{

   static D d;

   BOOST_STATIC_CONSTANT(bool, value = sizeof(cdf(d, 0.0f)) != 1);

};



template <class D>

struct has_quantile

{

   static D d;

   BOOST_STATIC_CONSTANT(bool, value = sizeof(quantile(d, 0.0f)) != 1);

};



template <class D>

struct is_distribution_imp

{

   BOOST_STATIC_CONSTANT(bool, value = 

      has_quantile<D>::value 

      && has_cdf<D>::value

      && has_value_type<D>::value

      && has_policy_type<D>::value);

};



template <class sig, sig val>

struct result_tag{};



template <class D>

double test_has_location(const volatile result_tag<typename D::value_type (D::*)()const, &D::location>*);

template <class D>

char test_has_location(...);



template <class D>

double test_has_scale(const volatile result_tag<typename D::value_type (D::*)()const, &D::scale>*);

template <class D>

char test_has_scale(...);



template <class D, bool b>

struct is_scaled_distribution_helper

{

   BOOST_STATIC_CONSTANT(bool, value = false);

};



template <class D>

struct is_scaled_distribution_helper<D, true>

{

   BOOST_STATIC_CONSTANT(bool, value = 

      (sizeof(test_has_location<D>(0)) != 1) 

      && 

      (sizeof(test_has_scale<D>(0)) != 1));

};



template <class D>

struct is_scaled_distribution_imp

{

   BOOST_STATIC_CONSTANT(bool, value = (::boost::math::tools::detail::is_scaled_distribution_helper<D, ::boost::math::tools::detail::is_distribution_imp<D>::value>::value));

};



} // namespace detail



BOOST_TT_AUX_BOOL_TRAIT_DEF1(is_distribution,T,::boost::math::tools::detail::is_distribution_imp<T>::value)

BOOST_TT_AUX_BOOL_TRAIT_DEF1(is_scaled_distribution,T,::boost::math::tools::detail::is_scaled_distribution_imp<T>::value)



}}}



#endif



