Skip to content

Commit

Permalink
Add documentation for the new type alias
Browse files Browse the repository at this point in the history
  • Loading branch information
Thomas Grützmacher committed Apr 11, 2024
1 parent bf7f2af commit 5d94d98
Showing 1 changed file with 216 additions and 4 deletions.
220 changes: 216 additions & 4 deletions core/test/utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,40 @@ namespace test {
namespace detail {


/**
* This structure creates a cartesian product of the types in the left list with
* the types of the right list and stores the combination in a std::tuple. The
* resulting type is a list (it will be the same type wrapper as the left and
* right list) of `std::tuple`.
* The wrapper / list type needs to be a structure that can take an arbitrary
* amount of types. An example for this wrapper is std::tuple, but a simple
* `template<typename... Args> struct wrapper {};` also works.
* Both the left and right list need to use the same wrapper, otherwise, the
* type specialization fails.
*
* This structure uses partial specialization to:
* - remove the OuterWrapper of both the left and right list;
* - extracts a single element of the left list and combines it with all
* elements of the right list;
* - after no elements remain in the left list, put all generated combinations
* together and wrap them in an OuterWrapper again
*
* This structure uses inheritance to store the combinations it creates in the
* parameter pack Result, which will be wrapped in the original OuterWrapper
* after all parameters from the LeftList have been processed (in the last
* specialization).
*
* Example:
* ```
* // Here, we use std::tuple as the outer type wrapper.
* using left_list = std::tuple<a1, a2, a3>;
* using right_list = std::tuple<b1, b2>;
* using result = typename cartesian_type_product<left_list, right_list>::type;
* // result = std::tuple<std::tuple<a1, b1>, std::tuple<a1, b2>,
* // std::tuple<a2, b1>, std::tuple<a2, b2>,
* // std::tuple<a3, b1>, std::tuple<a3, b2>>;
* ```
*/
template <typename LeftList, typename RightList, typename... Result>
struct cartesian_type_product {};

Expand All @@ -54,6 +88,28 @@ struct cartesian_type_product<OuterWrapper<>, OuterWrapper<RightArgs...>,
using type = OuterWrapper<Result...>;
};


/**
* This structure expects the left list to have all elements of the type
* std::tuple and the right list of elements you want to add to those tuples. It
* creates a new list where it adds all combinations of the std::tuple with the
* new element list as a new member of the std::tuple to the right side.
*
* It can be used to create a cartesian product with more than two lists by
* using the cartesian_type_product initially for the left argument, followed by
* this structure for each additional list.
* Example:
* ```
* template<typename... Args>
* using t = std::tuple<Args>; // use this alias to increase readability
* using left_combinations = t<t<a1, b1>, t<a1, b2>>;
* using right_new = t<n1, n2>;
* using new_list =
* typename add_to_cartesian_type_product<left_combinations,
* right_new>::type;
* // new_list = t<t<a1, b1, n1>, t<a1, b1, n2>, t<a1, b2, n1>, t<a1, b2, n2>>;
* ```
*/
template <typename ExistingCombinationList, typename NewElementList,
typename... Result>
struct add_to_cartesian_type_product {};
Expand All @@ -78,6 +134,22 @@ struct add_to_cartesian_type_product<
using type = OuterWrapper<Result...>;
};


/**
* Does the same as add_to_cartesian_type_product with the only difference that
* the new element will be added to the left side. The template parameter order
* is also flipped, so the new list is now on the left side.
* Example:
* ```
* template<typename... Args> using t = std::tuple<Args>;
* using right_combinations = t<t<a1, b1>, t<a1, b2>>;
* using left_new = t<n1, n2>;
* using new_list =
* typename add_to_cartesian_type_product_left<left_new,
* right_combinations>::type;
* // new_list = t<t<n1, a1, b1>, t<n2, a1, b1>, t<n1, a1, b2>, t<n2, a1, b2>>;
* ```
*/
template <typename NewElementList, typename ExistingCombinationList,
typename... Result>
struct add_to_cartesian_type_product_left {};
Expand All @@ -102,6 +174,14 @@ struct add_to_cartesian_type_product_left<OuterWrapper<NewElementArgs...>,
using type = OuterWrapper<Result...>;
};


/**
* Merges two lists into a single list.
* The left and right list need to use the same type wrapper, which will also be
* the resulting wrapper containing elements of both lists. The order of the
* left and right list are preserved. The resulting list will have all elements
* of the left list, followed by all elements of the right list.
*/
template <typename FirstList, typename SecondList>
struct merge_type_list {};

Expand All @@ -112,6 +192,17 @@ struct merge_type_list<OuterWrapper<Args1...>, OuterWrapper<Args2...>> {
};


/**
* This structure can change the outer type wrapper to the new, given one.
* Example:
* ```
* template <typename... Args>
* struct type_wrapper {};
* using old_list = std::tuple<int, double, short>;
* using new_list = typename change_outer_wrapper<type_wrapper, old_list>::type;
* // new_list = type_wrapper<int, double, short>;
* ```
*/
template <template <typename...> class NewOuterWrapper,
typename OldOuterWrapper>
struct change_outer_wrapper {};
Expand All @@ -123,6 +214,15 @@ struct change_outer_wrapper<NewOuterWrapper, OldOuterWrapper<Args...>> {
};


/**
* Creates a type list (the outer wrapper stays the same) where each original
* type is wrapped into the given NewInnerWrapper. Example:
* ```
* using new_type =
* typename add_internal_wrapper<std::complex,
* std::tuple<float, double>>::type;
* // new_type = std::tuple<std::complex<float>, std::complex<double>>;
*/
template <template <typename...> class NewInnerWrapper, typename ListType>
struct add_internal_wrapper {};

Expand All @@ -136,32 +236,144 @@ struct add_internal_wrapper<NewInnerWrapper, OuterWrapper<Args...>> {
} // namespace detail


/**
* This type alias creates a cartesian product of the types in the left list
* with the types of the right list and stores the combination in a std::tuple.
* The resulting type is a list (it will be the same type wrapper as the left
* and right list) of `std::tuple`.
* Example:
* ```
* // Here, we use std::tuple as the outer type wrapper.
* using left_list = std::tuple<a1, a2, a3>;
* using right_list = std::tuple<b1, b2>;
* using result = cartesian_type_product_t<left_list, right_list>;
* // result = std::tuple<std::tuple<a1, b1>, std::tuple<a1, b2>,
* // std::tuple<a2, b1>, std::tuple<a2, b2>,
* // std::tuple<a3, b1>, std::tuple<a3, b2>>;
* ```
*
* @tparam LeftList A wrapper type (like std::tuple) containing the list of
* types that you want to create the cartesian product with.
* The paremeters of this list will be the left type in the

Check warning on line 257 in core/test/utils.hpp

View workflow job for this annotation

GitHub Actions / Spell Check with Typos

"paremeters" should be "parameters".
* resulting `std::tuple`
* @tparam RightList Similar to the LeftList. Must use the same outer wrapper
* as the LeftList.
*/
template <typename LeftList, typename RightList>
using cartesian_type_product_t =
typename detail::cartesian_type_product<LeftList, RightList>::type;

/**
* This type alias is intended to be used with cartesian_type_product_t in order
* to create a more than two dimensional cartesian product by adding one element
* to the result per call.
* This structure expects the left list to have all elements of the type
* std::tuple (as it is returned from cartesian_type_product_t) and the right
* list of elements you want to add to those tuples.
* creates a new list where it adds all combinations of the std::tuple with the
* new element list as a new member of the std::tuple to the right side.
* Example:
* ```
* template<typename... Args>
* using t = std::tuple<Args>; // use this alias to increase readability
* using left_combinations = t<t<a1, b1>, t<a1, b2>>;
* using right_new = t<n1, n2>;
* using new_list =
* add_to_cartesian_type_product_t<left_combinations, right_new>;
* // new_list = t<t<a1, b1, n1>, t<a1, b1, n2>, t<a1, b2, n1>, t<a1, b2, n2>>;
* ```
*
* @tparam ExistingCombinationList An outer type wrapper containing different
* std::tuples that you want to add elements to
* @tparam NewElementList The list of new elements (using the same outer
* wrapper as ExistingCombinationList) you want to
* create all possible combinations with. These elements
* will be added to the right of each std::tuple
*/
template <typename ExistingCombinationList, typename NewElementList>
using add_to_cartesian_type_product_t =
typename detail::add_to_cartesian_type_product<ExistingCombinationList,
NewElementList>::type;

/**
* This type alias is very similar to add_to_cartesian_type_product_t. It only
* differs in where the new element is added to the `std::tuple`, which is to
* the left here, and the order of the parameter.
* Example:
* ```
* template<typename... Args> using t = std::tuple<Args>;
* using right_combinations = t<t<a1, b1>, t<a1, b2>>;
* using left_new = t<n1, n2>;
* using new_list =
* add_to_cartesian_type_product_left_t<left_new, right_combinations>;
* // new_list = t<t<n1, a1, b1>, t<n2, a1, b1>, t<n1, a1, b2>, t<n2, a1, b2>>;
* ```
*
* @tparam NewElementList The list of new elements (using the same outer
* wrapper as ExistingCombinationList) you want to
* create all possible combinations with. These elements
* will be added to the left of each std::tuple
* @tparam ExistingCombinationList An outer type wrapper containing different
* std::tuples that you want to add elements to
*/
template <typename NewElementList, typename ExistingCombinationList>
using add_to_cartesian_type_product_left_t =
typename detail::add_to_cartesian_type_product_left<
NewElementList, ExistingCombinationList>::type;

/**
* Merges two lists into a single list.
* The left and right list need to use the same type wrapper, which will also be
* the resulting wrapper containing elements of both lists. The order of the
* left and right list are preserved. The resulting list will have all elements
* of the left list, followed by all elements of the right list.
*
* @tparam FirstList The first list of types
* @tparam SecondList The second list of types. The type wrapper needs to be
* the same as for FirstList.
*/
template <typename FirstList, typename SecondList>
using merge_type_list_t =
typename detail::merge_type_list<FirstList, SecondList>::type;

template <template <typename...> class NewInnerWrapper, typename ListType>
using add_internal_wrapper_t =
typename detail::add_internal_wrapper<NewInnerWrapper, ListType>::type;

/**
* This type alias can change the outer type wrapper to the new, given one.
* Example:
* ```
* template <typename... Args>
* struct type_wrapper {};
* using old_list = std::tuple<int, double, short>;
* using new_list = change_outer_wrapper_t<type_wrapper, old_list>;
* // new_list = type_wrapper<int, double, short>;
* ```
*
* @tparam NewOuterWrapper the new wrapper you want to use as the new outer
* wrapper
* @tparam ListType The list of types where you want to replace the outer
* wrapper.
*/
template <template <typename...> class NewOuterWrapper, typename ListType>
using change_outer_wrapper_t =
typename detail::change_outer_wrapper<NewOuterWrapper, ListType>::type;

/**
* Creates a type list (the outer wrapper stays the same) where each original
* type is wrapped into the given NewInnerWrapper.
* Example:
* ```
* using new_type =
* add_internal_wrapper<std::complex, std::tuple<float, double>>;
* // new_type = std::tuple<std::complex<float>, std::complex<double>>;
* ```
*
* @tparam NewInnerWrapper the new wrapper you want to use to wrap each type
* in the list
* @tparam ListType The list of types where you want to add a wrapper to each
*/
template <template <typename...> class NewInnerWrapper, typename ListType>
using add_internal_wrapper_t =
typename detail::add_internal_wrapper<NewInnerWrapper, ListType>::type;


using RealValueTypes =
#if GINKGO_DPCPP_SINGLE_MODE
Expand Down

0 comments on commit 5d94d98

Please sign in to comment.