/////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga  2006-2007
//
// 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)
//
// See http://www.boost.org/libs/intrusive for documentation.
//
/////////////////////////////////////////////////////////////////////////////

#ifndef BOOST_INTRUSIVE_DETAIL_MPL_HPP
#define BOOST_INTRUSIVE_DETAIL_MPL_HPP

namespace boost {
namespace intrusive {
namespace detail {

typedef char one;
struct two {one _[2];};

template< bool C_ >
struct bool_
{
   static const bool value = C_;
};

typedef bool_<true>        true_;
typedef bool_<false>       false_;

typedef true_  true_type;
typedef false_ false_type;

typedef char yes_type;
struct no_type
{
   char padding[8];
};

template <bool B, class T = void>
struct enable_if_c {
  typedef T type;
};

template <class T>
struct enable_if_c<false, T> {};

template <class Cond, class T = void>
struct enable_if : public enable_if_c<Cond::value, T>{};

template <class T, class U>
class is_convertible
{
   typedef char true_t;
   class false_t { char dummy[2]; };
   static true_t dispatch(U);
   static false_t dispatch(...);
   static T trigger();
   public:
   static const bool value = sizeof(dispatch(trigger())) == sizeof(true_t);
};

template<
      bool C
    , typename T1
    , typename T2
    >
struct if_c
{
    typedef T1 type;
};

template<
      typename T1
    , typename T2
    >
struct if_c<false,T1,T2>
{
    typedef T2 type;
};

template<
      typename C
    , typename T1
    , typename T2
    >
struct if_
{
   typedef typename if_c<0 != C::value, T1, T2>::type type;
};

template<
      bool C
    , typename F1
    , typename F2
    >
struct eval_if_c
    : if_c<C,F1,F2>::type
{};

template<
      typename C
    , typename T1
    , typename T2
    >
struct eval_if
    : if_<C,T1,T2>::type
{};

// identity is an extension: it is not part of the standard.
template <class T>
struct identity
{
   typedef T type;
};

#if defined(BOOST_MSVC) || defined(__BORLANDC_)
#define BOOST_INTRUSIVE_TT_DECL __cdecl
#else
#define BOOST_INTRUSIVE_TT_DECL 
#endif

#if defined(_MSC_EXTENSIONS) && !defined(__BORLAND__)
#define BOOST_INTRUSIVE_TT_TEST_MSC_FUNC_SIGS
#endif

no_type BOOST_INTRUSIVE_TT_DECL is_function_ptr_tester(...);

template <class R >
yes_type is_function_ptr_tester(R (*)());

template <class R >
yes_type is_function_ptr_tester(R (*)( ...));

#ifdef BOOST_INTRUSIVE_TT_TEST_MSC_FUNC_SIGS
template <class R >
yes_type is_function_ptr_tester(R (__stdcall*)());
template <class R >
yes_type is_function_ptr_tester(R (__stdcall*)( ...));

template <class R >
yes_type is_function_ptr_tester(R (__fastcall*)());
template <class R >
yes_type is_function_ptr_tester(R (__fastcall*)( ...));

template <class R >
yes_type is_function_ptr_tester(R (__cdecl*)());
template <class R >
yes_type is_function_ptr_tester(R (__cdecl*)( ...));
#endif

template <class R , class T0 >
yes_type is_function_ptr_tester(R (*)( T0));

template <class R , class T0 >
yes_type is_function_ptr_tester(R (*)( T0 ...));

#ifdef BOOST_INTRUSIVE_TT_TEST_MSC_FUNC_SIGS
template <class R , class T0 >
yes_type is_function_ptr_tester(R (__stdcall*)( T0));
template <class R , class T0 >
yes_type is_function_ptr_tester(R (__stdcall*)( T0 ...));

template <class R , class T0 >
yes_type is_function_ptr_tester(R (__fastcall*)( T0));
template <class R , class T0 >
yes_type is_function_ptr_tester(R (__fastcall*)( T0 ...));

template <class R , class T0 >
yes_type is_function_ptr_tester(R (__cdecl*)( T0));
#endif
template <class R , class T0 , class T1 >
yes_type is_function_ptr_tester(R (*)( T0 , T1));

#ifdef BOOST_INTRUSIVE_TT_TEST_MSC_FUNC_SIGS
template <class R , class T0 , class T1 >
yes_type is_function_ptr_tester(R (__stdcall*)( T0 , T1));

template <class R , class T0 , class T1 >
yes_type is_function_ptr_tester(R (__fastcall*)( T0 , T1));

template <class R , class T0 , class T1 >
yes_type is_function_ptr_tester(R (__cdecl*)( T0 , T1));
#endif

template <typename T>
struct is_unary_or_binary_function_impl
{
   static T* t;
   static const bool value = sizeof(is_function_ptr_tester(t)) == sizeof(yes_type);
};

template <typename T>
struct is_unary_or_binary_function_impl<T&>
{
   static const bool value = false;
};

template<typename T>
struct is_unary_or_binary_function
{
   static const bool value = is_unary_or_binary_function_impl<T>::value;
};

//boost::alignment_of yields to 10K lines of preprocessed code, so we
//need an alternative
template <typename T> struct alignment_of;

template <typename T>
struct alignment_of_hack
{
    char c;
    T t;
    alignment_of_hack();
};

template <unsigned A, unsigned S>
struct alignment_logic
{
   static const std::size_t value = A < S ? A : S;
};

template< typename T >
struct alignment_of
{
   static const std::size_t value = alignment_logic
            < sizeof(alignment_of_hack<T>) - sizeof(T)
            , sizeof(T)
            >::value;
};

template <typename T, typename U>
struct is_same
{
   typedef char yes_type;
   struct no_type
   {
      char padding[8];
   };

   template <typename V>
   static yes_type is_same_tester(V*, V*);
   static no_type is_same_tester(...);

   static T *t;
   static U *u;

   static const bool value = sizeof(yes_type) == sizeof(is_same_tester(t,u));
};

template<typename T>
struct add_const
{  typedef const T type;   };

template<typename T>
struct remove_const
{  typedef  T type;   };

template<typename T>
struct remove_const<const T>
{  typedef T type;   };

template<class T>
struct remove_reference
{
   typedef T type;
};

template<class T>
struct remove_reference<T&>
{
   typedef T type;
};

template<class Class>
class is_empty_class
{
   template <typename T>
   struct empty_helper_t1 : public T
   {
      empty_helper_t1();
      int i[256];
   };

   struct empty_helper_t2
   { int i[256]; };

   public:
   static const bool value = sizeof(empty_helper_t1<Class>) == sizeof(empty_helper_t2);
};

} //namespace detail 
} //namespace intrusive 
} //namespace boost 

#endif //BOOST_INTRUSIVE_DETAIL_MPL_HPP
