Blob Blame Raw
#pragma once

#ifndef TCG_TRAITS_H
#define TCG_TRAITS_H

// tcg includes
#include "sfinae.h"

// STD includes
#include <iterator>

//--------------------------------------------------------------------------

namespace tcg {

//****************************************************************************
//    TCG traits for generic type concepts
//****************************************************************************

template <typename T>
struct traits {
  typedef T *pointer_type;
  typedef T pointed_type;
  typedef T &reference_type;
  typedef T referenced_type;
  typedef T element_type;
};

template <typename T>
struct traits<T *> {
  typedef T **pointer_type;
  typedef T pointed_type;
  typedef T *&reference_type;
  typedef T *referenced_type;
  typedef T *element_type;
};

template <typename T>
struct traits<T[]> : public traits<T *> {
  typedef T element_type;
};

template <typename T>
struct traits<T &> : public traits<T> {};

template <>
struct traits<void> {
  typedef void *pointer_type;
  typedef void pointed_type;
  typedef void reference_type;
  typedef void referenced_type;
};

//****************************************************************************
//    Qualifier removers
//****************************************************************************

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

template <typename T>
struct remove_ref {
  typedef T type;
};
template <typename T>
struct remove_ref<T &> {
  typedef T type;
};

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

//****************************************************************************
//    TCG traits for function types
//****************************************************************************

template <typename Func>
class function_traits {
  template <typename F, bool>
  struct result;

  template <typename F>
  struct result<F, true> {
    typedef typename F::result_type type;
  };

  template <typename F>
  struct result<F, false> {
    typedef struct { } type; };

  template <typename Q>
  static typename enable_if_exists<typename Q::result_type, char>::type
  result_fun(Q *);
  static double result_fun(...);

  template <typename F, bool>
  struct argument;

  template <typename F>
  struct argument<F, true> {
    typedef typename F::argument_type type;
  };

  template <typename F>
  struct argument<F, false> {
    typedef void type;
  };
  template <typename Q>

  static typename enable_if_exists<typename Q::argument_type, char>::type
  argument_fun(Q *);
  static double argument_fun(...);

  template <typename F, bool>
  struct first_arg;

  template <typename F>
  struct first_arg<F, true> {
    typedef typename F::first_argument_type type;
  };

  template <typename F>
  struct first_arg<F, false> {
    typedef void type;
  };
  template <typename Q>

  static typename enable_if_exists<typename Q::first_argument_type, char>::type
  first_arg_fun(Q *);
  static double first_arg_fun(...);

  template <typename F, bool>
  struct second_arg;

  template <typename F>
  struct second_arg<F, true> {
    typedef typename F::second_argument_type type;
  };

  template <typename F>
  struct second_arg<F, false> {
    typedef void type;
  };

  template <typename Q>
  static typename enable_if_exists<typename Q::second_argument_type, char>::type
  second_arg_fun(Q *);
  static double second_arg_fun(...);

public:
  enum {
    has_result =
        (sizeof(result_fun(typename tcg::traits<Func>::pointer_type())) ==
         sizeof(char)),
    has_argument =
        (sizeof(argument_fun(typename tcg::traits<Func>::pointer_type())) ==
         sizeof(char)),
    has_first_arg =
        (sizeof(first_arg_fun(typename tcg::traits<Func>::pointer_type())) ==
         sizeof(char)),
    has_second_arg =
        (sizeof(second_arg_fun(typename tcg::traits<Func>::pointer_type())) ==
         sizeof(char))
  };

  typedef typename result<Func, has_result>::type ret_type;
  typedef typename argument<Func, has_argument>::type arg_type;
  typedef typename first_arg<Func, has_first_arg>::type arg1_type;
  typedef typename second_arg<Func, has_second_arg>::type arg2_type;
};

//-----------------------------------------------------------------------

template <typename Ret>
struct function_traits<Ret()> {
  enum {
    has_result     = true,
    has_argument   = false,
    has_first_arg  = false,
    has_second_arg = false
  };

  typedef Ret ret_type;
  typedef void arg_type;
  typedef void arg1_type;
  typedef void arg2_type;
};

template <typename Ret>
struct function_traits<Ret (*)()> : public function_traits<Ret()> {};

template <typename Ret>
struct function_traits<Ret (&)()> : public function_traits<Ret()> {};

//-----------------------------------------------------------------------

template <typename Ret, typename Arg>
struct function_traits<Ret(Arg)> {
  enum {
    has_result     = true,
    has_argument   = true,
    has_first_arg  = false,
    has_second_arg = false
  };

  typedef Ret ret_type;
  typedef Arg arg_type;
  typedef void arg1_type;
  typedef void arg2_type;
};

template <typename Ret, typename Arg>
struct function_traits<Ret (*)(Arg)> : public function_traits<Ret(Arg)> {};

template <typename Ret, typename Arg>
struct function_traits<Ret (&)(Arg)> : public function_traits<Ret(Arg)> {};

//-----------------------------------------------------------------------

template <typename Ret, typename Arg1, typename Arg2>
struct function_traits<Ret(Arg1, Arg2)> {
  enum { has_result = true, has_first_arg = true, has_second_arg = true };

  typedef Ret ret_type;
  typedef Arg1 arg1_type;
  typedef Arg2 arg2_type;
};

template <typename Ret, typename Arg1, typename Arg2>
struct function_traits<Ret (*)(Arg1, Arg2)>
    : public function_traits<Ret(Arg1, Arg2)> {};

template <typename Ret, typename Arg1, typename Arg2>
struct function_traits<Ret (&)(Arg1, Arg2)>
    : public function_traits<Ret(Arg1, Arg2)> {};

//******************************************************************************
//    TCG traits for output container readers
//******************************************************************************

template <typename Reader, typename OutputData = typename Reader::value_type>
struct container_reader_traits {
  typedef Reader reader_type;
  typedef OutputData value_type;

  static void openContainer(reader_type &reader) { reader.openContainer(); }
  static void addElement(reader_type &reader, const value_type &data) {
    reader.addElement(data);
  }
  static void closeContainer(reader_type &reader) { reader.closeContainer(); }
};

//************************************************************************************
//    Notable Test  traits
//************************************************************************************

template <typename T>
struct is_floating_point {
  enum { value = false };
};

template <>
struct is_floating_point<float> {
  enum { value = true };
};

template <>
struct is_floating_point<double> {
  enum { value = true };
};

template <>
struct is_floating_point<long double> {
  enum { value = true };
};

//-----------------------------------------------------------------------

template <typename T>
struct is_function {
  enum { value = function_traits<T>::has_result };
};

template <typename T>
struct is_functor {
  template <typename Q>
  static typename enable_if_exists<typename Q::result_type, char>::type result(
      Q *);

  static double result(...);

  enum {
    value = (sizeof(result(typename tcg::traits<T>::pointer_type())) ==
             sizeof(char))
  };
};

}  // namespace tcg

#endif  // TCG_TRAITS_H