Added ListReduce, ListAll, and ListAny
These new features to VTK-m lists allow you to compute a single value from a list. `ListReduce` allows you to compute a value based on a predicate. `ListAll` and `ListAny` use this feature to determine if all or any of a list of `true_type` or `false_type` objects are true.
This commit is contained in:
parent
feac74a22a
commit
124f08381b
57
docs/changelog/new-list-features.md
Normal file
57
docs/changelog/new-list-features.md
Normal file
@ -0,0 +1,57 @@
|
||||
# New `vtkm::List` features
|
||||
|
||||
New features were added to those available in `vtkm/List.h`. These new
|
||||
features provide new operations on lists.
|
||||
|
||||
## Reductions
|
||||
|
||||
The new `vtkm::ListReduce` allows a reduction on a list. This template
|
||||
takes three arguments: a `vtkm::List`, an operation, and an initial value.
|
||||
The operation is itself a template that has two type arguments.
|
||||
|
||||
`vtkm::ListReduce` applies the initial value and the first item of the list
|
||||
to the operator. The result of that template is then iteratively applied to
|
||||
the operator with the next item in the list and so on.
|
||||
|
||||
``` cpp
|
||||
// Operation to use
|
||||
template <typename T1, typename T2>
|
||||
using Add = std::integral_constant<typename T1::type, T1::value + T2::value>;
|
||||
|
||||
using MyList = vtkm::List<std::integral_constant<int, 25>,
|
||||
std::integral_constant<int, 60>,
|
||||
std::integral_constant<int, 87>,
|
||||
std::integral_constant<int, 62>>;
|
||||
|
||||
using MySum = vtkm::ListReduce<MyList, Add, std::integral_constant<int, 0>>;
|
||||
// MySum becomes std::integral_constant<int, 234> (25+60+87+62 = 234)
|
||||
```
|
||||
|
||||
## All and Any
|
||||
|
||||
Because they are very common, two reductions that are automatically
|
||||
supported are `vtkm::ListAll` and `vtkm::ListAny`. These both take a
|
||||
`vtkm::List` containing either `std::true_type` or `std::false_type` (or
|
||||
some other "compatible" type that has a constant static `bool` named
|
||||
`value`). `vtkm::ListAll` will become `std::false_type` if any of the
|
||||
entries in the list are `std::false_type`. `vtkm::ListAny` becomes
|
||||
`std::true_type` if any of the entires in the list are `std::true_type`.
|
||||
|
||||
``` cpp
|
||||
using MyList = vtkm::List<std::integral_constant<int, 25>,
|
||||
std::integral_constant<int, 60>,
|
||||
std::integral_constant<int, 87>,
|
||||
std::integral_constant<int, 62>>;
|
||||
|
||||
template <typename T>
|
||||
using IsEven = std::integral_constant<bool, ((T % 2) == 0)>;
|
||||
|
||||
// Note that vtkm::ListTransform<MyList, IsEven> becomes
|
||||
// vtkm::List<std::false_type, std::true_type, std::false_type, std::true_type>
|
||||
|
||||
using AllEven = vtkm::ListAll<vtkm::ListTransform<MyList, IsEven>>;
|
||||
// AllEven becomes std::false_type
|
||||
|
||||
using AnyEven = vtkm::ListAny<vtkm::ListTransform<MyList, IsEven>>;
|
||||
// AnyEven becomes std::true_type
|
||||
```
|
77
vtkm/List.h
77
vtkm/List.h
@ -12,6 +12,8 @@
|
||||
|
||||
#include <vtkm/Types.h>
|
||||
|
||||
#include <vtkm/internal/Meta.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
|
||||
@ -807,6 +809,81 @@ template <typename List1, typename List2>
|
||||
using ListCross =
|
||||
typename detail::ListCrossImpl<internal::AsList<List1>, internal::AsList<List2>>::type;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template <typename L, template <typename T1, typename T2> class Operator, typename Result>
|
||||
struct ListReduceImpl;
|
||||
|
||||
template <template <typename T1, typename T2> class Operator, typename Result>
|
||||
struct ListReduceImpl<vtkm::List<>, Operator, Result>
|
||||
{
|
||||
using type = Result;
|
||||
};
|
||||
|
||||
template <typename T0,
|
||||
typename... Ts,
|
||||
template <typename O1, typename O2>
|
||||
class Operator,
|
||||
typename Result>
|
||||
struct ListReduceImpl<vtkm::List<T0, Ts...>, Operator, Result>
|
||||
{
|
||||
using type = typename ListReduceImpl<vtkm::List<Ts...>, Operator, Operator<Result, T0>>::type;
|
||||
};
|
||||
|
||||
template <typename T0,
|
||||
typename T1,
|
||||
typename T2,
|
||||
typename T3,
|
||||
typename T4,
|
||||
typename T5,
|
||||
typename T6,
|
||||
typename T7,
|
||||
typename T8,
|
||||
typename... Ts,
|
||||
template <typename O1, typename O2>
|
||||
class Operator,
|
||||
typename Result>
|
||||
struct ListReduceImpl<vtkm::List<T0, T1, T2, T3, T4, T5, T6, T7, T8, Ts...>, Operator, Result>
|
||||
{
|
||||
using type = typename ListReduceImpl<
|
||||
vtkm::List<T8, Ts...>,
|
||||
Operator,
|
||||
typename ListReduceImpl<vtkm::List<T0, T1, T2, T3, T4, T5, T6, T7>, Operator, Result>::type>::
|
||||
type;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/// \brief Reduces a list to a single type using an operator.
|
||||
///
|
||||
/// `ListReduce` takes a `vtkm::List`, an operator template, and an initial type. `ListReduce`
|
||||
/// first applies the initial type and the first item in the list to the operator and gets
|
||||
/// that type. That then applies the operator to that result and the next item in the list.
|
||||
/// This continues until a single value is left.
|
||||
///
|
||||
template <typename List, template <typename T1, typename T2> class Operator, typename Initial>
|
||||
using ListReduce = typename detail::ListReduceImpl<internal::AsList<List>, Operator, Initial>::type;
|
||||
|
||||
/// \brief Determines whether all the types in the list are "true."
|
||||
///
|
||||
/// `ListAll` expects a `vtkm::List` with types that have a `value` that is either true or false
|
||||
/// (such as `std::true_type` and `std::false_type`. Resolves to `std::true_type` if all the types
|
||||
/// are true, `std::false_type` otherwise. If the list is empty, resolves to `std::true_type`.
|
||||
///
|
||||
template <typename List>
|
||||
using ListAll = vtkm::ListReduce<List, vtkm::internal::meta::And, std::true_type>;
|
||||
|
||||
/// \brief Determines whether any of the types in the list are "true."
|
||||
///
|
||||
/// `ListAll` expects a `vtkm::List` with types that have a `value` that is either true or false
|
||||
/// (such as `std::true_type` and `std::false_type`. Resolves to `std::true_type` if any of the
|
||||
/// types are true, `std::false_type` otherwise. If the list is empty, resolves to
|
||||
/// `std::false_type`.
|
||||
///
|
||||
template <typename List>
|
||||
using ListAny = vtkm::ListReduce<List, vtkm::internal::meta::Or, std::false_type>;
|
||||
|
||||
#undef VTKM_CHECK_LIST_SIZE
|
||||
|
||||
} // namespace vtkm
|
||||
|
@ -68,6 +68,7 @@ set(headers
|
||||
IndexTag.h
|
||||
IndicesExtrude.h
|
||||
Invocation.h
|
||||
Meta.h
|
||||
Unreachable.h
|
||||
VariantImpl.h
|
||||
VariantImplDetail.h
|
||||
|
73
vtkm/internal/Meta.h
Normal file
73
vtkm/internal/Meta.h
Normal file
@ -0,0 +1,73 @@
|
||||
//============================================================================
|
||||
// Copyright (c) Kitware, Inc.
|
||||
// All rights reserved.
|
||||
// See LICENSE.txt for details.
|
||||
//
|
||||
// This software is distributed WITHOUT ANY WARRANTY; without even
|
||||
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
// PURPOSE. See the above copyright notice for more information.
|
||||
//============================================================================
|
||||
#ifndef vtk_m_internal_Meta_h
|
||||
#define vtk_m_internal_Meta_h
|
||||
|
||||
// This header file contains templates that are helpful with template metaprogramming.
|
||||
|
||||
// Perhaps one day these structures can be exposed in the public interface, but the
|
||||
// interface is a little wonky.
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace internal
|
||||
{
|
||||
namespace meta
|
||||
{
|
||||
|
||||
/// A simple `struct` that holds a type without having to actually make the type object.
|
||||
template <typename T>
|
||||
struct Type
|
||||
{
|
||||
using type = T;
|
||||
};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template <typename T1, typename T2>
|
||||
struct AndImpl : std::integral_constant<bool, T1::value && T2::value>
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T1, typename T2>
|
||||
struct OrImpl : std::integral_constant<bool, T1::value || T2::value>
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct NotImpl : std::integral_constant<bool, !T::value>
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/// Expects two types, both with a `value` constant static value (like a `std::integral_constant`).
|
||||
/// Resolves to a `std::integral_constant<bool, B>` where B is `T1::value && T2::value`.
|
||||
template <typename T1, typename T2>
|
||||
using And = typename detail::AndImpl<T1, T2>::type;
|
||||
|
||||
/// Expects two types, both with a `value` constant static value (like a `std::integral_constant`).
|
||||
/// Resolves to a `std::integral_constant<bool, B>` where B is `T1::value || T2::value`.
|
||||
template <typename T1, typename T2>
|
||||
using Or = typename detail::OrImpl<T1, T2>::type;
|
||||
|
||||
/// Expects a type with a `value` constant static value (like a std::integral_constant`).
|
||||
/// Resolves to a `std::integral_constant<bool, B>` where B is `!T::value`.
|
||||
template <typename T>
|
||||
using Not = typename detail::NotImpl<T>::type;
|
||||
|
||||
}
|
||||
}
|
||||
} // namespace vtkm::internal::meta
|
||||
|
||||
#endif //vtk_m_internal_Meta_h
|
@ -18,7 +18,7 @@ namespace
|
||||
{
|
||||
|
||||
template <int N>
|
||||
struct TestClass
|
||||
struct TestClass : std::integral_constant<int, N>
|
||||
{
|
||||
};
|
||||
|
||||
@ -63,6 +63,14 @@ struct EvenPredicate<TestClass<N>> : std::integral_constant<bool, (N % 2) == 0>
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using OddPredicate = vtkm::internal::meta::Not<EvenPredicate<T>>;
|
||||
|
||||
template <typename T1, typename T2>
|
||||
struct AddOperator : TestClass<T1::value + T2::value>
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T1, typename T2>
|
||||
void CheckSame(T1, T2)
|
||||
{
|
||||
@ -275,6 +283,27 @@ void TestLists()
|
||||
VTKM_TEST_ASSERT(!vtkm::ListHas<RepeatList, TestClass<0>>::value);
|
||||
VTKM_TEST_ASSERT(vtkm::ListHas<RepeatList, TestClass<1>>::value);
|
||||
VTKM_TEST_ASSERT(vtkm::ListHas<RepeatList, TestClass<14>>::value);
|
||||
|
||||
std::cout << "ListReduce" << std::endl;
|
||||
using Zero = std::integral_constant<int, 0>;
|
||||
VTKM_TEST_ASSERT((vtkm::ListReduce<SimpleCount, AddOperator, Zero>::value == 10));
|
||||
VTKM_TEST_ASSERT((vtkm::ListReduce<EvenList, AddOperator, Zero>::value == 20));
|
||||
VTKM_TEST_ASSERT((vtkm::ListReduce<LongList, AddOperator, Zero>::value == 105));
|
||||
VTKM_TEST_ASSERT((vtkm::ListReduce<RepeatList, AddOperator, Zero>::value == 27));
|
||||
|
||||
std::cout << "ListAll" << std::endl;
|
||||
VTKM_TEST_ASSERT(
|
||||
(vtkm::ListAll<vtkm::ListTransform<SimpleCount, EvenPredicate>>::value == false));
|
||||
VTKM_TEST_ASSERT((vtkm::ListAll<vtkm::ListTransform<EvenList, EvenPredicate>>::value == true));
|
||||
VTKM_TEST_ASSERT((vtkm::ListAll<vtkm::ListTransform<LongList, EvenPredicate>>::value == false));
|
||||
VTKM_TEST_ASSERT((vtkm::ListAll<vtkm::List<>>::value == true));
|
||||
|
||||
std::cout << "ListAny" << std::endl;
|
||||
VTKM_TEST_ASSERT((vtkm::ListAny<vtkm::ListTransform<SimpleCount, EvenPredicate>>::value == true));
|
||||
VTKM_TEST_ASSERT((vtkm::ListAny<vtkm::ListTransform<EvenList, EvenPredicate>>::value == true));
|
||||
VTKM_TEST_ASSERT((vtkm::ListAny<vtkm::ListTransform<EvenList, OddPredicate>>::value == false));
|
||||
VTKM_TEST_ASSERT((vtkm::ListAny<vtkm::ListTransform<LongList, EvenPredicate>>::value == true));
|
||||
VTKM_TEST_ASSERT((vtkm::ListAny<vtkm::List<>>::value == false));
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
Loading…
Reference in New Issue
Block a user