// C++0x type_traits -*- C++ -*-

// Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library.  This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// Under Section 7 of GPL version 3, you are granted additional
// permissions described in the GCC Runtime Library Exception, version
// 3.1, as published by the Free Software Foundation.

// You should have received a copy of the GNU General Public License and
// a copy of the GCC Runtime Library Exception along with this program;
// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
// <http://www.gnu.org/licenses/>.

/** @file include/type_traits
 *  This is a Standard C++ Library header.
 */

#ifndef _GLIBCXX_TYPE_TRAITS
#define _GLIBCXX_TYPE_TRAITS 1

#pragma GCC system_header

#ifndef __GXX_EXPERIMENTAL_CXX0X__
# include <bits/c++0x_warning.h>
#else

#if defined(_GLIBCXX_INCLUDE_AS_TR1)
#  error C++0x header cannot be included from TR1 header
#endif

#include <cstddef>

#if defined(_GLIBCXX_INCLUDE_AS_CXX0X)
#  include <tr1_impl/type_traits>
#else
#  define _GLIBCXX_INCLUDE_AS_CXX0X
#  define _GLIBCXX_BEGIN_NAMESPACE_TR1
#  define _GLIBCXX_END_NAMESPACE_TR1
#  define _GLIBCXX_TR1
#  include <tr1_impl/type_traits>
#  undef _GLIBCXX_TR1
#  undef _GLIBCXX_END_NAMESPACE_TR1
#  undef _GLIBCXX_BEGIN_NAMESPACE_TR1
#  undef _GLIBCXX_INCLUDE_AS_CXX0X
#endif

namespace std
{
  /**
   * @addtogroup metaprogramming
   * @{
   */

  // Primary classification traits.

  /// is_lvalue_reference
  template<typename>
    struct is_lvalue_reference
    : public false_type { };

  template<typename _Tp>
    struct is_lvalue_reference<_Tp&>
    : public true_type { };

  /// is_rvalue_reference
  template<typename>
    struct is_rvalue_reference
    : public false_type { };

  template<typename _Tp>
    struct is_rvalue_reference<_Tp&&>
    : public true_type { };

  // Secondary classification traits.

  /// is_reference
  template<typename _Tp>
    struct is_reference
    : public integral_constant<bool, (is_lvalue_reference<_Tp>::value
				      || is_rvalue_reference<_Tp>::value)>
    { };

  // Reference transformations.

  /// remove_reference
  template<typename _Tp>
    struct remove_reference
    { typedef _Tp   type; };

  template<typename _Tp>
    struct remove_reference<_Tp&>
    { typedef _Tp   type; };

  template<typename _Tp>
    struct remove_reference<_Tp&&>
    { typedef _Tp   type; };

  template<typename _Tp,
	   bool = !is_reference<_Tp>::value && !is_void<_Tp>::value,
	   bool = is_rvalue_reference<_Tp>::value>
    struct __add_lvalue_reference_helper
    { typedef _Tp   type; };

  template<typename _Tp>
    struct __add_lvalue_reference_helper<_Tp, true, false>
    { typedef _Tp&   type; };

  template<typename _Tp>
    struct __add_lvalue_reference_helper<_Tp, false, true>
    { typedef typename remove_reference<_Tp>::type&   type; };

  /// add_lvalue_reference
  template<typename _Tp>
    struct add_lvalue_reference
    : public __add_lvalue_reference_helper<_Tp>
    { };

  template<typename _Tp,
	   bool = !is_reference<_Tp>::value && !is_void<_Tp>::value>
    struct __add_rvalue_reference_helper
    { typedef _Tp   type; };

  template<typename _Tp>
    struct __add_rvalue_reference_helper<_Tp, true>
    { typedef _Tp&&   type; };

  /// add_rvalue_reference
  template<typename _Tp>
    struct add_rvalue_reference
    : public __add_rvalue_reference_helper<_Tp>
    { };

  // Scalar properties and transformations.

  template<typename _Tp,
	   bool = is_integral<_Tp>::value,
	   bool = is_floating_point<_Tp>::value>
    struct __is_signed_helper
    : public false_type { };

  template<typename _Tp>
    struct __is_signed_helper<_Tp, false, true>
    : public true_type { };

  template<typename _Tp>
    struct __is_signed_helper<_Tp, true, false>
    : public integral_constant<bool, static_cast<bool>(_Tp(-1) < _Tp(0))>
    { };

  /// is_signed
  template<typename _Tp>
    struct is_signed
    : public integral_constant<bool, __is_signed_helper<_Tp>::value>
    { };

  /// is_unsigned
  template<typename _Tp>
    struct is_unsigned
    : public integral_constant<bool, (is_arithmetic<_Tp>::value
				      && !is_signed<_Tp>::value)>
    { };

  // Member introspection.

  /// is_trivial
  template<typename _Tp>
    struct is_trivial
    : public integral_constant<bool, __is_trivial(_Tp)>
    { };

  /// is_standard_layout
  template<typename _Tp>
    struct is_standard_layout
    : public integral_constant<bool, __is_standard_layout(_Tp)>
    { };

  /// is_pod
  // Could use is_standard_layout && is_trivial instead of the builtin.
  template<typename _Tp>
    struct is_pod
    : public integral_constant<bool, __is_pod(_Tp)>
    { };

  template<typename _Tp>
    typename add_rvalue_reference<_Tp>::type declval();

  template<typename _Tp, typename... _Args>
    class __is_constructible_helper
    : public __sfinae_types
    {
      template<typename _Tp1, typename... _Args1>
        static decltype(_Tp1(declval<_Args1>()...), __one()) __test(int);

      template<typename, typename...>
        static __two __test(...);

    public:
      static const bool __value = sizeof(__test<_Tp, _Args...>(0)) == 1;
    };

  template<typename _Tp, typename _Arg>
    class __is_constructible_helper<_Tp, _Arg>
    : public __sfinae_types
    {
      template<typename _Tp1, typename _Arg1>
        static decltype(static_cast<_Tp1>(declval<_Arg1>()), __one())
	__test(int);

      template<typename, typename>
        static __two __test(...);

    public:
      static const bool __value = sizeof(__test<_Tp, _Arg>(0)) == 1;
    };

  /// is_constructible
  // XXX FIXME
  // The C++0x specifications require front-end support, see N2255.
  template<typename _Tp, typename... _Args>
    struct is_constructible
    : public integral_constant<bool,
			       __is_constructible_helper<_Tp,
							 _Args...>::__value>
    { };

  /// has_trivial_default_constructor
  template<typename _Tp>
    struct has_trivial_default_constructor
    : public integral_constant<bool, __has_trivial_constructor(_Tp)>
    { };

  /// has_trivial_copy_constructor
  template<typename _Tp>
    struct has_trivial_copy_constructor
    : public integral_constant<bool, __has_trivial_copy(_Tp)>
    { };

  /// has_trivial_assign
  template<typename _Tp>
    struct has_trivial_assign
    : public integral_constant<bool, __has_trivial_assign(_Tp)>
    { };

  /// has_trivial_destructor
  template<typename _Tp>
    struct has_trivial_destructor
    : public integral_constant<bool, __has_trivial_destructor(_Tp)>
    { };

  /// has_nothrow_default_constructor
  template<typename _Tp>
    struct has_nothrow_default_constructor
    : public integral_constant<bool, __has_nothrow_constructor(_Tp)>
    { };

  /// has_nothrow_copy_constructor
  template<typename _Tp>
    struct has_nothrow_copy_constructor
    : public integral_constant<bool, __has_nothrow_copy(_Tp)>
    { };

  /// has_nothrow_assign
  template<typename _Tp>
    struct has_nothrow_assign
    : public integral_constant<bool, __has_nothrow_assign(_Tp)>
    { };

  // Relationships between types.

  /// is_base_of
  template<typename _Base, typename _Derived>
    struct is_base_of
    : public integral_constant<bool, __is_base_of(_Base, _Derived)>
    { };

  template<typename _From, typename _To,
	   bool = (is_void<_From>::value || is_void<_To>::value
		   || is_function<_To>::value || is_array<_To>::value)>
    struct __is_convertible_helper
    { static const bool __value = (is_void<_From>::value
				   && is_void<_To>::value); };

  template<typename _From, typename _To>
    class __is_convertible_helper<_From, _To, false>
    : public __sfinae_types
    {
      static __one __test(_To);
      static __two __test(...);

    public:
      static const bool __value = sizeof(__test(declval<_From>())) == 1;
    };

  /// is_convertible
  // XXX FIXME
  // The C++0x specifications require front-end support, see N2255.
  template<typename _From, typename _To>
    struct is_convertible
    : public integral_constant<bool,
			       __is_convertible_helper<_From, _To>::__value>
    { };

  /// is_explicitly_convertible
  template<typename _From, typename _To>
    struct is_explicitly_convertible
    : public is_constructible<_To, _From>
    { };

  template<std::size_t _Len>
    struct __aligned_storage_msa
    { 
      union __type
      {
	unsigned char __data[_Len];
	struct __attribute__((__aligned__)) { } __align; 
      };
    };

  /**
   *  @brief Alignment type.
   *
   *  The value of _Align is a default-alignment which shall be the
   *  most stringent alignment requirement for any C++ object type
   *  whose size is no greater than _Len (3.9). The member typedef
   *  type shall be a POD type suitable for use as uninitialized
   *  storage for any object whose size is at most _Len and whose
   *  alignment is a divisor of _Align.
  */
  template<std::size_t _Len, std::size_t _Align =
	   __alignof__(typename __aligned_storage_msa<_Len>::__type)>
    struct aligned_storage
    { 
      union type
      {
	unsigned char __data[_Len];
	struct __attribute__((__aligned__((_Align)))) { } __align; 
      };
    };


  // Define a nested type if some predicate holds.
  // Primary template.
  /// enable_if
  template<bool, typename _Tp = void>
    struct enable_if 
    { };

  // Partial specialization for true.
  template<typename _Tp>
    struct enable_if<true, _Tp>
    { typedef _Tp type; };


  // A conditional expression, but for types. If true, first, if false, second.
  // Primary template.
  /// conditional
  template<bool _Cond, typename _Iftrue, typename _Iffalse>
    struct conditional
    { typedef _Iftrue type; };

  // Partial specialization for false.
  template<typename _Iftrue, typename _Iffalse>
    struct conditional<false, _Iftrue, _Iffalse>
    { typedef _Iffalse type; };


  // Decay trait for arrays and functions, used for perfect forwarding
  // in make_pair, make_tuple, etc.
  template<typename _Up, 
	   bool _IsArray = is_array<_Up>::value,
	   bool _IsFunction = is_function<_Up>::value> 
    struct __decay_selector;

  // NB: DR 705.
  template<typename _Up> 
    struct __decay_selector<_Up, false, false>
    { typedef typename remove_cv<_Up>::type __type; };

  template<typename _Up> 
    struct __decay_selector<_Up, true, false>
    { typedef typename remove_extent<_Up>::type* __type; };

  template<typename _Up> 
    struct __decay_selector<_Up, false, true>
    { typedef typename add_pointer<_Up>::type __type; };

  /// decay
  template<typename _Tp> 
    class decay 
    { 
      typedef typename remove_reference<_Tp>::type __remove_type;

    public:
      typedef typename __decay_selector<__remove_type>::__type type;
    };


  // Utility for constructing identically cv-qualified types.
  template<typename _Unqualified, bool _IsConst, bool _IsVol>
    struct __cv_selector;

  template<typename _Unqualified>
    struct __cv_selector<_Unqualified, false, false>
    { typedef _Unqualified __type; };

  template<typename _Unqualified>
    struct __cv_selector<_Unqualified, false, true>
    { typedef volatile _Unqualified __type; };

  template<typename _Unqualified>
    struct __cv_selector<_Unqualified, true, false>
    { typedef const _Unqualified __type; };

  template<typename _Unqualified>
    struct __cv_selector<_Unqualified, true, true>
    { typedef const volatile _Unqualified __type; };

  template<typename _Qualified, typename _Unqualified,
	   bool _IsConst = is_const<_Qualified>::value,
	   bool _IsVol = is_volatile<_Qualified>::value>
    class __match_cv_qualifiers
    {
      typedef __cv_selector<_Unqualified, _IsConst, _IsVol> __match;

    public:
      typedef typename __match::__type __type; 
    };


  // Utility for finding the unsigned versions of signed integral types.
  template<typename _Tp>
    struct __make_unsigned
    { typedef _Tp __type; };

  template<>
    struct __make_unsigned<char>
    { typedef unsigned char __type; };

  template<>
    struct __make_unsigned<signed char>
    { typedef unsigned char __type; };

  template<>
    struct __make_unsigned<short>
    { typedef unsigned short __type; };

  template<>
    struct __make_unsigned<int>
    { typedef unsigned int __type; };

  template<>
    struct __make_unsigned<long>
    { typedef unsigned long __type; };

  template<>
    struct __make_unsigned<long long>
    { typedef unsigned long long __type; };


  // Select between integral and enum: not possible to be both.
  template<typename _Tp, 
	   bool _IsInt = is_integral<_Tp>::value,
	   bool _IsEnum = is_enum<_Tp>::value>
    class __make_unsigned_selector;

  template<typename _Tp>
    class __make_unsigned_selector<_Tp, true, false>
    {
      typedef __make_unsigned<typename remove_cv<_Tp>::type> __unsignedt;
      typedef typename __unsignedt::__type __unsigned_type;
      typedef __match_cv_qualifiers<_Tp, __unsigned_type> __cv_unsigned;

    public:
      typedef typename __cv_unsigned::__type __type;
    };

  template<typename _Tp>
    class __make_unsigned_selector<_Tp, false, true>
    {
      // With -fshort-enums, an enum may be as small as a char.
      typedef unsigned char __smallest;
      static const bool __b0 = sizeof(_Tp) <= sizeof(__smallest);
      static const bool __b1 = sizeof(_Tp) <= sizeof(unsigned short);
      static const bool __b2 = sizeof(_Tp) <= sizeof(unsigned int);
      typedef conditional<__b2, unsigned int, unsigned long> __cond2;
      typedef typename __cond2::type __cond2_type;
      typedef conditional<__b1, unsigned short, __cond2_type> __cond1;
      typedef typename __cond1::type __cond1_type;

    public:
      typedef typename conditional<__b0, __smallest, __cond1_type>::type __type;
    };

  // Given an integral/enum type, return the corresponding unsigned
  // integer type.
  // Primary template.
  /// make_unsigned
  template<typename _Tp>
    struct make_unsigned 
    { typedef typename __make_unsigned_selector<_Tp>::__type type; };

  // Integral, but don't define.
  template<>
    struct make_unsigned<bool>;


  // Utility for finding the signed versions of unsigned integral types.
  template<typename _Tp>
    struct __make_signed
    { typedef _Tp __type; };

  template<>
    struct __make_signed<char>
    { typedef signed char __type; };

  template<>
    struct __make_signed<unsigned char>
    { typedef signed char __type; };

  template<>
    struct __make_signed<unsigned short>
    { typedef signed short __type; };

  template<>
    struct __make_signed<unsigned int>
    { typedef signed int __type; };

  template<>
    struct __make_signed<unsigned long>
    { typedef signed long __type; };

  template<>
    struct __make_signed<unsigned long long>
    { typedef signed long long __type; };


  // Select between integral and enum: not possible to be both.
  template<typename _Tp, 
	   bool _IsInt = is_integral<_Tp>::value,
	   bool _IsEnum = is_enum<_Tp>::value>
    class __make_signed_selector;

  template<typename _Tp>
    class __make_signed_selector<_Tp, true, false>
    {
      typedef __make_signed<typename remove_cv<_Tp>::type> __signedt;
      typedef typename __signedt::__type __signed_type;
      typedef __match_cv_qualifiers<_Tp, __signed_type> __cv_signed;

    public:
      typedef typename __cv_signed::__type __type;
    };

  template<typename _Tp>
    class __make_signed_selector<_Tp, false, true>
    {
      // With -fshort-enums, an enum may be as small as a char.
      typedef signed char __smallest;
      static const bool __b0 = sizeof(_Tp) <= sizeof(__smallest);
      static const bool __b1 = sizeof(_Tp) <= sizeof(signed short);
      static const bool __b2 = sizeof(_Tp) <= sizeof(signed int);
      typedef conditional<__b2, signed int, signed long> __cond2;
      typedef typename __cond2::type __cond2_type;
      typedef conditional<__b1, signed short, __cond2_type> __cond1;
      typedef typename __cond1::type __cond1_type;

    public:
      typedef typename conditional<__b0, __smallest, __cond1_type>::type __type;
    };

  // Given an integral/enum type, return the corresponding signed
  // integer type.
  // Primary template.
  /// make_signed
  template<typename _Tp>
    struct make_signed 
    { typedef typename __make_signed_selector<_Tp>::__type type; };

  // Integral, but don't define.
  template<>
    struct make_signed<bool>;

  /// common_type
  template<typename... _Tp>
    struct common_type;

  template<typename _Tp>
    struct common_type<_Tp>
    { typedef _Tp type; };

  template<typename _Tp, typename _Up>
    struct common_type<_Tp, _Up>
    { typedef decltype(true ? declval<_Tp>() : declval<_Up>()) type; };

  template<typename _Tp, typename _Up, typename... _Vp>
    struct common_type<_Tp, _Up, _Vp...>
    {
      typedef typename
        common_type<typename common_type<_Tp, _Up>::type, _Vp...>::type type;
    };
  // @} group metaprogramming

  /// declval
  template<typename _Tp>
    struct __declval_protector
    {
      static const bool __stop = false;
      static typename add_rvalue_reference<_Tp>::type __delegate();
    };

  template<typename _Tp>
    inline typename add_rvalue_reference<_Tp>::type
    declval()
    {
      static_assert(__declval_protector<_Tp>::__stop,
		    "declval() must not be used!");
      return __declval_protector<_Tp>::__delegate();
    }
}

#endif  // __GXX_EXPERIMENTAL_CXX0X__

#endif  // _GLIBCXX_TYPE_TRAITS
