// mpl_trace.hpp
//
// Copyright (c) 2008,2009  Steven Watanabe
// Copyright (c) 2009       Troy D. Straszheim 
//
// 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)
//
//
//  To use: #define BOOST_MPL_ENABLE_TRACE before you #include this
//  file.  Pepper your classes with BOOST_MPL_TRACE(this_type), eg:
//
//  template <typename T>
//  struct traceme
//  {
//    BOOST_MPL_TRACE(traceme<T>);
//  };
// 
//  These BOOST_MPL_TRACEs you can leave in your code.  If
//  #BOOST_MPL_TRACE isn't defined, they will compile out.
//  
//  To enable trace of a particular class/template, specialize
//  boost::mpl::trace::enable, like this:
//
//  template <typename T> struct enable<traceme<T> > : boost::mpl::true_ { };
//

#ifndef BOOST_MPL_TRACE_HPP_INCLUDED
#define BOOST_MPL_TRACE_HPP_INCLUDED

#include <boost/mpl/bool.hpp>

namespace boost {
  namespace mpl {
    namespace trace {

      //
      //  Always visible, so that things compile when BOOST_MPL_ENABLE_TRACE is off
      //
      template <typename T> 
      struct enable : boost::mpl::false_ { };

#ifdef BOOST_MPL_ENABLE_TRACE

#if defined(_MSC_VER)

      struct incomplete;

#define BOOST_MPL_TRACE_IMPL()						\
      enum trace_test {							\
	trace_value =							\
	sizeof(delete ((::boost::mpl::trace::incomplete*)0),0)		\
      };
  
#elif defined(__GNUC__)
#if (__GNUC__ < 4) || (__GNUC_MINOR__ < 3)

      template<int N>
      struct int_ {
	enum { value = N };
	typedef int type;
      };
      template<class T>
      struct make_zero {
	enum { value = 0 };
      };
      extern int value;
      
      char template_trace_size_one(...);

#define BOOST_MPL_TRACE_IMPL()						\
    struct boost_mpl_trace_test {};					\
	enum {								\
	  trace_size =							\
	  sizeof(template_trace_size_one(static_cast<boost_mpl_trace_test*>(0))) }; \
	    typedef ::boost::mpl::trace::int_				\
	    <sizeof(::boost::mpl::trace::value /			\
		    ::boost::mpl::trace::make_zero<			\
		    ::boost::mpl::trace::int_<				\
		    trace_size						\
		    >							\
		    >::value)						\
	    > boost_mpl_trace_result;
#else
    // gcc 4.3 and over

      int f() __attribute__((deprecated));
      int f(double);

#define BOOST_MPL_TRACE_IMPL()				\
    enum { value = sizeof(::boost::mpl::trace::f()) }

#endif

#else
#  error Unknown compiler
#endif

    template <typename T, typename U = void>
    struct impl
    { };

    template <typename U>
    struct impl<boost::mpl::true_, U>
    {
      BOOST_MPL_TRACE_IMPL();
    };

#define BOOST_MPL_TRACE(T) ::boost::mpl::trace::impl< typename ::boost::mpl::trace::enable< T >::type, T > tracer

#else // BOOST_MPL_ENABLE_TRACE

#define BOOST_MPL_TRACE(T)

#endif // BOOST_MPL_ENABLE_TRACE
    } // namespace trace
  } // namespace mpl
} // namespace boost

#endif // BOOST_MPL_TRACE_HPP_INCLUDED

