diff --git a/nvbench/detail/type_list_impl.h b/nvbench/detail/type_list_impl.h index e4aaf78..e8b0a10 100644 --- a/nvbench/detail/type_list_impl.h +++ b/nvbench/detail/type_list_impl.h @@ -7,7 +7,14 @@ namespace nvbench { template -struct type_list; +struct type_list +{}; + +template +struct wrapped_type +{ + using type = T; +}; namespace tl { @@ -83,6 +90,23 @@ struct cartesian_product< using type = decltype(detail::concat(cur{}, next{})); }; +//------------------------------------------------------------------------------ +template +void foreach (std::index_sequence, Functor && f) +{ + // Garmonbozia... + ((f(wrapped_type(TypeList{}))>{})), ...); +} + +template +void foreach (Functor &&f) +{ + constexpr std::size_t list_size = decltype(detail::size(TypeList{}))::value; + using indices = std::make_index_sequence; + + detail::foreach(indices{}, std::forward(f)); +} + } // namespace detail } // namespace tl } // namespace nvbench diff --git a/nvbench/type_list.cuh b/nvbench/type_list.cuh index 68b9a65..57fc1f6 100644 --- a/nvbench/type_list.cuh +++ b/nvbench/type_list.cuh @@ -9,8 +9,11 @@ namespace nvbench { template -struct type_list -{}; +struct type_list; + +// Wraps a type for use with nvbench::tl::foreach. +template +struct wrapped_type; namespace tl { @@ -99,6 +102,26 @@ using prepend_each = typename detail::prepend_each::type; template using cartesian_product = typename detail::cartesian_product::type; +/** + * Invoke the Functor once for each type in TypeList. The type will be passed to + * `f` as a `nvbench::wrapped_type` argument. + * + * ```c++ + * using TL = nvbench::type_list; + * std::vector sizes; + * nvbench::tl::foreach([&sizes](auto wrapped_type) { + * using T = typename decltype(wrapped_type)::type; + * sizes.push_back(sizeof(T)); + * }); + * static_assert(sizes == {1, 2, 3, 4}); + * ``` + */ +template +void foreach (Functor &&f) +{ + detail::foreach(std::forward(f)); +} + } // namespace tl } // namespace nvbench diff --git a/testing/CMakeLists.txt b/testing/CMakeLists.txt index b54d0e2..91a96ff 100644 --- a/testing/CMakeLists.txt +++ b/testing/CMakeLists.txt @@ -7,6 +7,7 @@ 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_include_directories(${test_name} PRIVATE "${CMAKE_CURRENT_LIST_DIR}") target_link_libraries(${test_name} PRIVATE nvbench fmt) set_target_properties(${test_name} PROPERTIES COMPILE_FEATURES cuda_std_17) add_test(NAME ${test_name} COMMAND "$") diff --git a/testing/int64_axis.cu b/testing/int64_axis.cu index 38199a9..0644689 100644 --- a/testing/int64_axis.cu +++ b/testing/int64_axis.cu @@ -1,6 +1,6 @@ #include -#include "testing/test_asserts.cuh" +#include "test_asserts.cuh" #include diff --git a/testing/type_list.cu b/testing/type_list.cu index f67c8f6..a4d86e7 100644 --- a/testing/type_list.cu +++ b/testing/type_list.cu @@ -2,8 +2,15 @@ #include +#include "test_asserts.cuh" + +#include +#include + #include +#include #include +#include // Unique, numbered types for testing type_list functionality. using T0 = std::integral_constant; @@ -103,5 +110,37 @@ struct test_cartesian_product static_assert(std::is_same_v, CartProd>); }; -// This test only has static asserts. -int main() {} +struct test_foreach +{ + using TL0 = nvbench::type_list<>; + using TL1 = nvbench::type_list; + using TL2 = nvbench::type_list; + using TL3 = nvbench::type_list; + + template + static void test(std::vector ref_vals) + { + std::vector test_vals; + nvbench::tl::foreach([&test_vals](auto wrapped_type) { + using T = typename decltype(wrapped_type)::type; + test_vals.push_back(nvbench::type_strings::input_string()); + }); + ASSERT_MSG(test_vals == ref_vals, + fmt::format("{} != {}", test_vals, ref_vals)); + } + + static void run() + { + test({}); + test({"T0"}); + test({"T0", "T1"}); + test({"T0", "T1", "T2"}); + } +}; + +int main() +{ + // Note that most tests in this file are just static asserts. Only those with + // runtime components are listed here. + test_foreach::run(); +}