text: #include <c10/util/TypeList.h>
  #include <gtest/gtest.h>
  #include <memory>
  
  using namespace c10::guts::typelist;
  
  namespace test_size {
      class MyClass {};
      static_assert(0 == size<typelist<>>::value, "");
      static_assert(1 == size<typelist<int>>::value, "");
      static_assert(3 == size<typelist<int, float&, const MyClass&&>>::value, "");
  }
  
  namespace test_from_tuple {
      class MyClass {};
      static_assert(std::is_same<typelist<int, float&, const MyClass&&>, from_tuple_t<std::tuple<int, float&, const MyClass&&>>>::value, "");
      static_assert(std::is_same<typelist<>, from_tuple_t<std::tuple<>>>::value, "");
  }
  
  namespace test_to_tuple {
      class MyClass {};
      static_assert(std::is_same<std::tuple<int, float&, const MyClass&&>, to_tuple_t<typelist<int, float&, const MyClass&&>>>::value, "");
      static_assert(std::is_same<std::tuple<>, to_tuple_t<typelist<>>>::value, "");
  }
  
  namespace test_concat {
      class MyClass {};
      static_assert(std::is_same<typelist<>, concat_t<>>::value, "");
      static_assert(std::is_same<typelist<>, concat_t<typelist<>>>::value, "");
      static_assert(std::is_same<typelist<>, concat_t<typelist<>, typelist<>>>::value, "");
      static_assert(std::is_same<typelist<int>, concat_t<typelist<int>>>::value, "");
      static_assert(std::is_same<typelist<int>, concat_t<typelist<int>, typelist<>>>::value, "");
      static_assert(std::is_same<typelist<int>, concat_t<typelist<>, typelist<int>>>::value, "");
      static_assert(std::is_same<typelist<int>, concat_t<typelist<>, typelist<int>, typelist<>>>::value, "");
      static_assert(std::is_same<typelist<int, float&>, concat_t<typelist<int>, typelist<float&>>>::value, "");
      static_assert(std::is_same<typelist<int, float&>, concat_t<typelist<>, typelist<int, float&>, typelist<>>>::value, "");
      static_assert(std::is_same<typelist<int, float&, const MyClass&&>, concat_t<typelist<>, typelist<int, float&>, typelist<const MyClass&&>>>::value, "");
  }
  
  namespace test_filter {
      class MyClass {};
      static_assert(std::is_same<typelist<>, filter_t<std::is_reference, typelist<>>>::value, "");
      static_assert(std::is_same<typelist<>, filter_t<std::is_reference, typelist<int, float, double, MyClass>>>::value, "");
      static_assert(std::is_same<typelist<float&, const MyClass&&>, filter_t<std::is_reference, typelist<int, float&, double, const MyClass&&>>>::value, "");
  }
  
  namespace test_count_if {
      class MyClass final {};
      static_assert(count_if<std::is_reference, typelist<int, bool&, const MyClass&&, float, double>>::value == 2, "");
      static_assert(count_if<std::is_reference, typelist<int, bool>>::value == 0, "");
      static_assert(count_if<std::is_reference, typelist<>>::value == 0, "");
  }
  
  namespace test_true_for_each_type {
      template<class> class Test;
      class MyClass {};
      static_assert(true_for_each_type<std::is_reference, typelist<int&, const float&&, const MyClass&>>::value, "");
      static_assert(!true_for_each_type<std::is_reference, typelist<int&, const float, const MyClass&>>::value, "");
      static_assert(true_for_each_type<std::is_reference, typelist<>>::value, "");
  }
  
  namespace test_map {
      class MyClass {};
      static_assert(std::is_same<typelist<>, map_t<c10::guts::add_lvalue_reference_t, typelist<>>>::value, "");
      static_assert(std::is_same<typelist<int&>, map_t<c10::guts::add_lvalue_reference_t, typelist<int>>>::value, "");
      static_assert(std::is_same<typelist<int&, double&, const MyClass&>, map_t<c10::guts::add_lvalue_reference_t, typelist<int, double, const MyClass>>>::value, "");
  }
  
  namespace test_head {
      class MyClass {};
      static_assert(std::is_same<int, head_t<typelist<int, double>>>::value, "");
      static_assert(std::is_same<const MyClass&, head_t<typelist<const MyClass&, double>>>::value, "");
      static_assert(std::is_same<MyClass&&, head_t<typelist<MyClass&&, MyClass>>>::value, "");
      static_assert(std::is_same<bool, head_t<typelist<bool>>>::value, "");
  }
  
  namespace test_reverse {
      class MyClass {};
      static_assert(std::is_same<
              typelist<int, double, MyClass*, const MyClass&&>,
              reverse_t<typelist<const MyClass&&, MyClass*, double, int>>
      >::value, "");
      static_assert(std::is_same<
              typelist<>,
              reverse_t<typelist<>>
      >::value, "");
  }
  
  namespace test_map_types_to_values {
      struct map_to_size {
        template<class T> constexpr size_t operator()(T) const {return sizeof(typename T::type);}
      };
  
      TEST(TypeListTest, MapTypesToValues_sametype) {
          auto sizes =
              map_types_to_values<typelist<int64_t, bool, uint32_t>>(map_to_size());
          std::tuple<size_t, size_t, size_t> expected(8, 1, 4);
          static_assert(std::is_same<decltype(expected), decltype(sizes)>::value, "");
          EXPECT_EQ(expected, sizes);
      }
  
      struct map_make_shared {
        template<class T> std::shared_ptr<typename T::type> operator()(T) {
          return std::make_shared<typename T::type>();
        }
      };
  
      TEST(TypeListTest, MapTypesToValues_differenttypes) {
          auto shared_ptrs =
                  map_types_to_values<typelist<int, double>>(map_make_shared());
          static_assert(std::is_same<std::tuple<std::shared_ptr<int>, std::shared_ptr<double>>, decltype(shared_ptrs)>::value, "");
      }
  
      struct Class1 {static int func() {return 3;}};
      struct Class2 {static double func() {return 2.0;}};
  
      struct mapper_call_func {
        template<class T> auto operator()(T) -> decltype(T::type::func()) { return T::type::func(); }
      };
  
      TEST(TypeListTest, MapTypesToValues_members) {
          auto result =
                  map_types_to_values<typelist<Class1, Class2>>(mapper_call_func());
          std::tuple<int, double> expected(3, 2.0);
          static_assert(std::is_same<decltype(expected), decltype(result)>::value, "");
          EXPECT_EQ(expected, result);
      }
  
      struct mapper_call_nonexistent_function {
        template<class T> auto operator()(T) -> decltype(T::type::this_doesnt_exist()) { return T::type::this_doesnt_exist(); }
      };
  
      TEST(TypeListTest, MapTypesToValues_empty) {
          auto result =
                  map_types_to_values<typelist<>>(mapper_call_nonexistent_function());
          std::tuple<> expected;
          static_assert(std::is_same<decltype(expected), decltype(result)>::value, "");
          EXPECT_EQ(expected, result);
      }
  }
  
  namespace test_find_if {
    static_assert(0 == find_if<typelist<char&>, std::is_reference>::value, "");
    static_assert(0 == find_if<typelist<char&, int, char&, int&>, std::is_reference>::value, "");
    static_assert(2 == find_if<typelist<char, int, char&, int&>, std::is_reference>::value, "");
    static_assert(3 == find_if<typelist<char, int, char, int&>, std::is_reference>::value, "");
  }
  
  namespace test_contains {
    static_assert(contains<typelist<double>, double>::value, "");
    static_assert(contains<typelist<int, double>, double>::value, "");
    static_assert(!contains<typelist<int, double>, float>::value, "");
    static_assert(!contains<typelist<>, double>::value, "");
  }
  