text: // This file is part of Eigen, a lightweight C++ template library
  // for linear algebra.
  //
  // Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
  //
  // This Source Code Form is subject to the terms of the Mozilla
  // Public License v. 2.0. If a copy of the MPL was not distributed
  // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
  
  #ifndef EIGEN_EMULATE_CXX11_META_H
  #define EIGEN_EMULATE_CXX11_META_H
  
  
  
  namespace Eigen {
  
  namespace internal {
  
  /** \internal
    * \file CXX11/util/EmulateCXX11Meta.h
    * This file emulates a subset of the functionality provided by CXXMeta.h for
    * compilers that don't yet support cxx11 such as nvcc.
    */
  
  struct empty_list { static const std::size_t count = 0; };
  
  template<typename T, typename Tail=empty_list> struct type_list {
    typedef T HeadType;
    typedef Tail TailType;
    static const T head;
    static const Tail tail;
    static const std::size_t count = 1 + Tail::count;
  };
  
  struct null_type { };
  
  template<typename T1 = null_type, typename T2 = null_type, typename T3 = null_type,
           typename T4 = null_type, typename T5 = null_type, typename T6 = null_type,
           typename T7 = null_type, typename T8 = null_type>
  struct make_type_list {
    typedef typename make_type_list<T2, T3, T4, T5, T6, T7, T8>::type tailresult;
  
    typedef type_list<T1, tailresult> type;
  };
  
  template<> struct make_type_list<> {
    typedef empty_list type;
  };
  
  
  template <std::size_t index, class TList> struct get_type;
  
  template <class Head, class Tail>
  struct get_type<0, type_list<Head, Tail> >
  {
    typedef Head type;
  };
  
  template <std::size_t i, class Head, class Tail>
  struct get_type<i, type_list<Head, Tail> >
  {
    typedef typename get_type<i-1, Tail>::type type;
  };
  
  
  /* numeric list */
  template <typename T, T n>
  struct type2val {
    typedef T type;
    static const T value = n;
  };
  
  
  template<typename T, size_t n, T V> struct gen_numeric_list_repeated;
  
  template<typename T, T V> struct gen_numeric_list_repeated<T, 1, V> {
    typedef typename make_type_list<type2val<T, V> >::type type;
  };
  
  template<typename T, T V> struct gen_numeric_list_repeated<T, 2, V> {
    typedef typename make_type_list<type2val<T, V>, type2val<T, V> >::type type;
  };
  
  template<typename T, T V> struct gen_numeric_list_repeated<T, 3, V> {
    typedef typename make_type_list<type2val<T, V>, type2val<T, V>, type2val<T, V> >::type type;
  };
  
  template<typename T, T V> struct gen_numeric_list_repeated<T, 4, V> {
    typedef typename make_type_list<type2val<T, V>, type2val<T, V>, type2val<T, V>, type2val<T, V> >::type type;
  };
  
  template<typename T, T V> struct gen_numeric_list_repeated<T, 5, V> {
    typedef typename make_type_list<type2val<T, V>, type2val<T, V>, type2val<T, V>, type2val<T, V>, type2val<T, V> >::type type;
  };
  
  template<typename T, T V> struct gen_numeric_list_repeated<T, 6, V> {
    typedef typename make_type_list<type2val<T, V>, type2val<T, V>, type2val<T, V>,
                                    type2val<T, V>, type2val<T, V>, type2val<T, V> >::type type;
  };
  
  template<typename T, T V> struct gen_numeric_list_repeated<T, 7, V> {
    typedef typename make_type_list<type2val<T, V>, type2val<T, V>, type2val<T, V>,
                                    type2val<T, V>, type2val<T, V>, type2val<T, V>,
                                    type2val<T, V> >::type type;
  };
  
  template<typename T, T V> struct gen_numeric_list_repeated<T, 8, V> {
    typedef typename make_type_list<type2val<T, V>, type2val<T, V>, type2val<T, V>,
                                    type2val<T, V>, type2val<T, V>, type2val<T, V>,
                                    type2val<T, V>, type2val<T, V> >::type type;
  };
  
  
  template <std::size_t index, class NList> struct get;
  
  template <std::size_t i>
  struct get<i, empty_list>
  {
    get() { eigen_assert(false && "index overflow"); }
    typedef void type;
    static const char value = '\0';
  };
  
  template <std::size_t i, class Head>
  struct get<i, type_list<Head, empty_list> >
  {
    get() { eigen_assert(false && "index overflow"); }
    typedef void type;
    static const char value = '\0';
  };
  
  template <class Head>
  struct get<0, type_list<Head, empty_list> >
  {
    typedef typename Head::type type;
    static const type value = Head::value;
  };
  
  template <class Head, class Tail>
  struct get<0, type_list<Head, Tail> >
  {
    typedef typename Head::type type;
    static const type value = Head::value;
  };
  
  template <std::size_t i, class Head, class Tail>
  struct get<i, type_list<Head, Tail> >
  {
    typedef typename Tail::HeadType::type type;
    static const type value = get<i-1, Tail>::value;
  };
  
  
  template <class NList> struct arg_prod {
    static const typename NList::HeadType::type value = get<0, NList>::value * arg_prod<typename NList::TailType>::value;
  };
  template <> struct arg_prod<empty_list> {
    static const int value = 1;
  };
  
  
  template<int n, typename t>
  array<t, n> repeat(t v) {
    array<t, n> array;
    array.fill(v);
    return array;
  }
  
  template<std::size_t I, class Head, class Tail>
  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE typename Head::type array_get(type_list<Head, Tail>&) {
    return get<I, type_list<Head, Tail> >::value;
  }
  template<std::size_t I, class Head, class Tail>
  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE typename Head::type array_get(const type_list<Head, Tail>&) {
    return get<I, type_list<Head, Tail> >::value;
  }
  
  template <class NList>
  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE typename NList::HeadType::type array_prod(const NList&) {
    return arg_prod<NList>::value;
  }
  
  template<typename t, std::size_t n>
  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE t array_prod(const array<t, n>& a) {
    t prod = 1;
    for (size_t i = 0; i < n; ++i) { prod *= a[i]; }
    return prod;
  }
  template<typename t>
  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE t array_prod(const array<t, 0>& /*a*/) {
    return 0;
  }
  
  template<typename t>
  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE t array_prod(const std::vector<t>& a) {
    eigen_assert(a.size() > 0);
    t prod = 1;
    for (size_t i = 0; i < a.size(); ++i) { prod *= a[i]; }
    return prod;
  }
  
  
  template<std::size_t I, class T>
  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T& array_get(std::vector<T>& a) {
    return a[I];
  }
  template<std::size_t I, class T>
  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const T& array_get(const std::vector<T>& a) {
    return a[I];
  }
  
  struct sum_op {
    template<typename A, typename B> static inline bool run(A a, B b) { return a + b; }
  };
  struct product_op {
    template<typename A, typename B> static inline bool run(A a, B b) { return a * b; }
  };
  
  struct logical_and_op {
    template<typename A, typename B> static inline bool run(A a, B b) { return a && b; }
  };
  struct logical_or_op {
    template<typename A, typename B> static inline bool run(A a, B b) { return a || b; }
  };
  
  struct equal_op {
    template<typename A, typename B> static inline bool run(A a, B b) { return a == b; }
  };
  struct not_equal_op {
    template<typename A, typename B> static inline bool run(A a, B b) { return a != b; }
  };
  struct lesser_op {
    template<typename A, typename B> static inline bool run(A a, B b) { return a < b; }
  };
  struct lesser_equal_op {
    template<typename A, typename B> static inline bool run(A a, B b) { return a <= b; }
  };
  
  struct greater_op {
    template<typename A, typename B> static inline bool run(A a, B b) { return a > b; }
  };
  struct greater_equal_op {
    template<typename A, typename B> static inline bool run(A a, B b) { return a >= b; }
  };
  
  struct not_op {
    template<typename A> static inline bool run(A a) { return !a; }
  };
  struct negation_op {
    template<typename A> static inline bool run(A a) { return -a; }
  };
  struct greater_equal_zero_op {
    template<typename A> static inline bool run(A a) { return a >= 0; }
  };
  
  
  template<typename Reducer, typename Op, typename A, std::size_t N>
  struct ArrayApplyAndReduce {
    static inline bool run(const array<A, N>& a) {
      EIGEN_STATIC_ASSERT(N >= 2, YOU_MADE_A_PROGRAMMING_MISTAKE);
      bool result = Reducer::run(Op::run(a[0]), Op::run(a[1]));
      for (size_t i = 2; i < N; ++i) {
        result = Reducer::run(result, Op::run(a[i]));
      }
      return result;
    }
  };
  
  template<typename Reducer, typename Op, typename A>
  struct ArrayApplyAndReduce<Reducer, Op, A, 1>  {
    static inline bool run(const array<A, 1>& a) {
      return Op::run(a[0]);
    }
  };
  
  template<typename Reducer, typename Op, typename A, std::size_t N>
  inline bool array_apply_and_reduce(const array<A, N>& a) {
    return ArrayApplyAndReduce<Reducer, Op, A, N>::run(a);
  }
  
  template<typename Reducer, typename Op, typename A, typename B, std::size_t N>
  struct ArrayZipAndReduce {
    static inline bool run(const array<A, N>& a, const array<B, N>& b) {
      EIGEN_STATIC_ASSERT(N >= 2, YOU_MADE_A_PROGRAMMING_MISTAKE);
      bool result = Reducer::run(Op::run(a[0], b[0]), Op::run(a[1], b[1]));
      for (size_t i = 2; i < N; ++i) {
        result = Reducer::run(result, Op::run(a[i], b[i]));
      }
      return result;
    }
  };
  
  template<typename Reducer, typename Op, typename A, typename B>
  struct ArrayZipAndReduce<Reducer, Op, A, B, 1> {
    static inline bool run(const array<A, 1>& a, const array<B, 1>& b) {
      return Op::run(a[0], b[0]);
    }
  };
  
  template<typename Reducer, typename Op, typename A, typename B, std::size_t N>
  inline bool array_zip_and_reduce(const array<A, N>& a, const array<B, N>& b) {
    return ArrayZipAndReduce<Reducer, Op, A, B, N>::run(a, b);
  }
  
  }  // end namespace internal
  
  }  // end namespace Eigen
  
  
  
  #endif  // EIGEN_EMULATE_CXX11_META_H
  