Add nvbench::type_list.

This commit is contained in:
Allison Vacanti
2020-12-20 21:09:47 -05:00
parent 4462460947
commit 014d94e402
5 changed files with 280 additions and 0 deletions

View File

@@ -13,6 +13,13 @@ CPMAddPackage(
"RUN_HAVE_STD_REGEX 0"
)
# Why does CMake make it so difficult to enable cuda C++17 with interface
# properties...Resorting to brute force to unblock.
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAG} -std=c++17")
add_library(nvbench INTERFACE)
target_include_directories(nvbench INTERFACE "${CMAKE_CURRENT_LIST_DIR}")
target_link_libraries(nvbench INTERFACE benchmark_main)
set_target_properties(nvbench PROPERTIES INTERFACE_COMPILE_FEATURES cuda_std_17)
add_subdirectory(testing)

View File

@@ -0,0 +1,84 @@
#pragma once
#include <cstdint>
#include <tuple>
namespace nvbench
{
template <typename... Ts>
struct type_list;
namespace tl
{
namespace detail
{
template <std::size_t I, typename... Ts>
auto get(nvbench::type_list<Ts...>)
-> std::tuple_element_t<I, std::tuple<Ts...>>;
template <typename... Ts, typename... Us>
auto concat(nvbench::type_list<Ts...>, nvbench::type_list<Us...>)
-> nvbench::type_list<Ts..., Us...>;
//------------------------------------------------------------------------------
template <typename T, typename TLs>
struct prepend_each;
template <typename T>
struct prepend_each<T, nvbench::type_list<>>
{
using type = nvbench::type_list<>;
};
template <typename T, typename TL, typename... TLTail>
struct prepend_each<T, nvbench::type_list<TL, TLTail...>>
{
using cur = decltype(detail::concat(nvbench::type_list<T>{}, TL{}));
using next =
typename detail::prepend_each<T, nvbench::type_list<TLTail...>>::type;
using type = decltype(detail::concat(nvbench::type_list<cur>{}, next{}));
};
//------------------------------------------------------------------------------
template <typename TLs>
struct cartesian_product;
template <>
struct cartesian_product<nvbench::type_list<>>
{
using type = nvbench::type_list<>;
};
template <typename... TLTail>
struct cartesian_product<nvbench::type_list<nvbench::type_list<>, TLTail...>>
{
using type = nvbench::type_list<>;
};
template <typename T, typename... Ts>
struct cartesian_product<nvbench::type_list<nvbench::type_list<T, Ts...>>>
{
using cur = nvbench::type_list<nvbench::type_list<T>>;
using next = typename detail::cartesian_product<
nvbench::type_list<nvbench::type_list<Ts...>>>::type;
using type = decltype(detail::concat(cur{}, next{}));
};
template <typename T, typename... Tail, typename TL, typename... TLTail>
struct cartesian_product<
nvbench::type_list<nvbench::type_list<T, Tail...>, TL, TLTail...>>
{
using tail_prod =
typename detail::cartesian_product<nvbench::type_list<TL, TLTail...>>::type;
using cur = typename detail::prepend_each<T, tail_prod>::type;
using next = typename detail::cartesian_product<
nvbench::type_list<nvbench::type_list<Tail...>, TL, TLTail...>>::type;
using type = decltype(detail::concat(cur{}, next{}));
};
} // namespace detail
} // namespace tl
} // namespace nvbench

93
nvbench/type_list.h Normal file
View File

@@ -0,0 +1,93 @@
#pragma once
#include "detail/type_list_impl.h"
#include <tuple>
#include <type_traits>
namespace nvbench
{
template <typename... Ts>
struct type_list
{};
namespace tl
{
/**
* Get the TypeList entry at the specified index.
*
* ```c++
* using TL = nvbench::type_list<T0, T1, T2, T3, T4>;
* static_assert(std::is_same_v<nvbench::tl::get<0, TL>, T0>);
* static_assert(std::is_same_v<nvbench::tl::get<1, TL>, T1>);
* static_assert(std::is_same_v<nvbench::tl::get<2, TL>, T2>);
* static_assert(std::is_same_v<nvbench::tl::get<3, TL>, T3>);
* static_assert(std::is_same_v<nvbench::tl::get<4, TL>, T4>);
* ```
*/
template <std::size_t Index, typename TypeList>
using get = decltype(detail::get<Index>(TypeList{}));
/**
* Concatenate two type_lists.
*
* ```c++
* using TL01 = nvbench::type_list<T0, T1>;
* using TL23 = nvbench::type_list<T2, T3>;
* using TL0123 = nvbench::type_list<T0, T1, T2, T3>;
* static_assert(std::is_same_v<nvbench::tl::concat<TL01, TL23>, T0123>);
* ```
*/
template <typename TypeList1, typename TypeList2>
using concat = decltype(detail::concat(TypeList1{}, TypeList2{}));
/**
* Given a type `T` and a type_list of type_lists `TypeLists`, create
* a new type_list containing each entry from TypeLists prepended with T.
*
* ```c++
* using TypeLists = type_list<type_list<T0, T1>,
* type_list<T2, T3>>;
* using Result = nvbench::tl::prepend_each<T, TypeLists>;
* using Reference = type_list<type_list<T, T0, T1>,
* type_list<T, T2, T3>>;
* static_assert(std::is_same_v<Result, Reference>);
* ```
*/
template <typename T, typename TypeLists>
using prepend_each = typename detail::prepend_each<T, TypeLists>::type;
/**
* Given a type_list of type_lists, compute the cartesian product across all
* nested type_lists. Supports arbitrary numbers and sizes of nested type_lists.
*
* Beware that the result grows very quickly in size.
*
* ```c++
* using T01 = type_list<T0, T1>;
* using U012 = type_list<U0, U1, U2>;
* using V01 = type_list<V0, V1>;
* using TLs = type_list<T01, U012, V01>;
* using CartProd = type_list<type_list<T0, U0, V0>,
* type_list<T0, U0, V1>,
* type_list<T0, U1, V0>,
* type_list<T0, U1, V1>,
* type_list<T0, U2, V0>,
* type_list<T0, U2, V1>,
* type_list<T1, U0, V0>,
* type_list<T1, U0, V1>,
* type_list<T1, U1, V0>,
* type_list<T1, U1, V1>,
* type_list<T1, U2, V0>,
* type_list<T1, U2, V1>>;
* static_assert(std::is_same_v<bench::tl::cartesian_product<TLs>, CartProd>);
* ```
*/
template <typename TLs>
using cartesian_product = typename detail::cartesian_product<TLs>::type;
} // namespace tl
} // namespace nvbench

12
testing/CMakeLists.txt Normal file
View File

@@ -0,0 +1,12 @@
set(test_srcs
type_list.cu
)
foreach(test_src IN LISTS test_srcs)
get_filename_component(test_name "${test_src}" NAME_WLE)
string(PREPEND test_name "nvbench.test.")
add_executable(${test_name} "${test_src}")
target_link_libraries(${test_name} PRIVATE nvbench)
set_target_properties(${test_name} PROPERTIES COMPILE_FEATURES cuda_std_17)
add_test(NAME ${test_name} COMMAND "$<TARGET_FILE:${test_target}>")
endforeach()

84
testing/type_list.cu Normal file
View File

@@ -0,0 +1,84 @@
#include <nvbench/type_list.h>
#include <cstdint>
#include <type_traits>
// Unique, numbered types for testing type_list functionality.
using T0 = std::integral_constant<std::size_t, 0>;
using T1 = std::integral_constant<std::size_t, 1>;
using T2 = std::integral_constant<std::size_t, 2>;
using T3 = std::integral_constant<std::size_t, 3>;
using T4 = std::integral_constant<std::size_t, 4>;
using T5 = std::integral_constant<std::size_t, 5>;
using T6 = std::integral_constant<std::size_t, 6>;
using T7 = std::integral_constant<std::size_t, 7>;
struct test_get
{
using TL = nvbench::type_list<T0, T1, T2, T3, T4, T5>;
static_assert(std::is_same_v<T0, nvbench::tl::get<0, TL>>);
static_assert(std::is_same_v<T1, nvbench::tl::get<1, TL>>);
static_assert(std::is_same_v<T2, nvbench::tl::get<2, TL>>);
static_assert(std::is_same_v<T3, nvbench::tl::get<3, TL>>);
static_assert(std::is_same_v<T4, nvbench::tl::get<4, TL>>);
static_assert(std::is_same_v<T5, nvbench::tl::get<5, TL>>);
};
struct test_concat
{
using TLEmpty = nvbench::type_list<>;
using TL012 = nvbench::type_list<T0, T1, T2>;
using TL765 = nvbench::type_list<T7, T6, T5>;
struct empty_tests
{
static_assert(
std::is_same_v<nvbench::tl::concat<TLEmpty, TLEmpty>, TLEmpty>);
static_assert(std::is_same_v<nvbench::tl::concat<TLEmpty, TL012>, TL012>);
static_assert(std::is_same_v<nvbench::tl::concat<TL012, TLEmpty>, TL012>);
};
static_assert(std::is_same_v<nvbench::tl::concat<TL012, TL765>,
nvbench::type_list<T0, T1, T2, T7, T6, T5>>);
};
struct test_prepend_each
{
using T = void;
using T01 = nvbench::type_list<T0, T1>;
using T23 = nvbench::type_list<T2, T3>;
using TLs = nvbench::type_list<T01, T23>;
using Expected = nvbench::type_list<nvbench::type_list<T, T0, T1>,
nvbench::type_list<T, T2, T3>>;
static_assert(std::is_same_v<nvbench::tl::prepend_each<T, TLs>, Expected>);
};
struct test_cartesian_product
{
using U0 = T2;
using U1 = T3;
using U2 = T4;
using V0 = T5;
using V1 = T6;
using T01 = nvbench::type_list<T0, T1>;
using U012 = nvbench::type_list<U0, U1, U2>;
using V01 = nvbench::type_list<V0, V1>;
using TLs = nvbench::type_list<T01, U012, V01>;
using CartProd = nvbench::type_list<nvbench::type_list<T0, U0, V0>,
nvbench::type_list<T0, U0, V1>,
nvbench::type_list<T0, U1, V0>,
nvbench::type_list<T0, U1, V1>,
nvbench::type_list<T0, U2, V0>,
nvbench::type_list<T0, U2, V1>,
nvbench::type_list<T1, U0, V0>,
nvbench::type_list<T1, U0, V1>,
nvbench::type_list<T1, U1, V0>,
nvbench::type_list<T1, U1, V1>,
nvbench::type_list<T1, U2, V0>,
nvbench::type_list<T1, U2, V1>>;
static_assert(std::is_same_v<nvbench::tl::cartesian_product<TLs>, CartProd>);
};
// This test only has static asserts.
int main() {}