Commit 9d16fadf authored by Kenneth Moreland's avatar Kenneth Moreland Committed by Kitware Robot
Browse files

Merge topic 'vec-initializer-lists'

15789443 Enable Vec construction with intializer_list of single value
79afe2a1 Simplify make_ArrayHandleSwizzle
ae8d994d

 Add support for initializer lists in Vec
Acked-by: Kitware Robot's avatarKitware Robot <kwrobot@kitware.com>
Acked-by: Allison Vacanti's avatarAllison Vacanti <allison.vacanti@kitware.com>
Merge-request: !1239
parents 0200fcbf 15789443
# Support initializer lists for Vec
Add constructors to the `vtkm::Vec` classes that accept `std::initializer_list`. The
main advantage of this addition is that it makes it much easier to initialize `Vec`s
of arbitrary length.
Although previously some `Vec` classes could be constructed with values listed in
their parameters, that only worked for initializes up to size 4.
``` cpp
vtkm::Vec<vtkm::Float64, 3> vec1{1.1, 2.2, 3.3}; // New better initializer
vtkm::Vec<vtkm::Float64, 3> vec2 = {1.1, 2.2, 3.3}; // Nice syntax also supported by
// initializer lists.
vtkm::Vec<vtkm::Float64, 3> vec3(1.1, 2.2, 3.3); // Old style that still works but
// probably should be deprecated.
```
Nested initializer lists work to initialize `Vec`s of `Vec`s.
``` cpp
vtkm::Vec<vtkm::Vec<vtkm::Float64, 2>, 3> vec{ {1.1, 2.2}, {3.3, 4.4}, {5.5, 6.6} };
```
The nice thing about the `std::initializer_list` implementation is that it works for any
size `Vec`. That keeps us from jumping through hoops for larger `Vec`s.
``` cpp
vtkm::Vec<vtkm::Float64, 5> vec1{1.1, 2.2, 3.3, 4.4, 5.5}; // Works fine.
vtkm::Vec<vtkm::Float64, 5> vec2(1.1, 2.2, 3.3, 4.4, 5.5); // ERROR! This constructor
// not implemented!
```
If a `vtkm::Vec` is initialized with a list of size one, then that one value is
replicated for all components.
``` cpp
vtkm::Vec<vtkm::Float64, 3> vec{1.1}; // vec gets [ 1.1, 1.1, 1.1 ]
```
This "scalar" initialization also works for `Vec`s of `Vec`s.
``` cpp
vtkm::Vec<vtkm::Vec<vtkm::Float64, 2>, 3> vec1{ { 1.1, 2.2 } };
// vec1 is [[1.1, 2.2], [1.1, 2.2], [1.1, 2.2]]
vtkm::Vec<vtkm::Vec<vtkm::Float64, 2>, 3> vec2{ { 3.3}, { 4.4 }, { 5.5 } };
// vec2 is [[3.3, 3.3], [4.4, 4.4], [5.5, 5.5]]
```
`vtkm::make_Vec` is also updated to support an arbitrary number initial values.
``` cpp
// Creates a vtkm::Vec<vtkm::Float64, 5>
auto vec = vtkm::make_Vec(1.1, 2.2, 3.3, 4.4, 5.5);
```
This is super convenient when dealing with variadic function arguments.
``` cpp
template <typename... Ts>
void ExampleVariadicFunction(const Ts&... params)
{
auto vec = vtkm::make_Vec(params...);
```
Of course, this assumes that the type of all the parameters is the same. If not, you
could run into compiler trouble.
There is also a version of `vtkm::make_Vec` that accepts an `std::initializer_list`,
but it is not very useful because you have to separately specify the length of the
`Vec` (due to some limitations of `std::initializer_list` in C++11).
``` cpp
// Creates a vtkm::Vec<vtkm::Float64, 3>
auto vec1 = vtkm::make_Vec<3>({1.1, 2.2, 3.3});
// Creates exactly the same thing
auto vec2 = vtkm::Vec<vtkm::Float64, 3>{1.1, 2.2, 3.3};
```
A limitation of the initializer list constructor is that the compiler has no way to
check the length of the list or force it to a particular length. Thus it is entirely
possible to construct a `Vec` with the wrong number of arguments. Or, more to the
point, the compiler will let you do it, but there is an assert in the constructor to
correct for that. (Of course, asserts are not compiled in release builds.)
``` cpp
// This will compile, but it's results are undefined when it is run.
// In debug builds, it will fail an assert.
vtkm::Vec<vtkm::Float64, 3> vec{1.1, 1.2};
```
......@@ -625,6 +625,31 @@ protected:
}
}
VTKM_EXEC_CONT
VecBase(std::initializer_list<ComponentType> values)
{
ComponentType* dest = this->Components;
auto src = values.begin();
if (values.size() == 1)
{
for (vtkm::IdComponent i = 0; i < Size; ++i)
{
this->Components[i] = *src;
++dest;
}
}
else
{
VTKM_ASSERT((values.size() == NUM_COMPONENTS) &&
"Vec object initialized wrong number of components.");
for (; src != values.end(); ++src)
{
*dest = *src;
++dest;
}
}
}
#if (!(defined(VTKM_CUDA) && (__CUDACC_VER_MAJOR__ < 8)))
#if (defined(VTKM_GCC) || defined(VTKM_CLANG))
#pragma GCC diagnostic push
......@@ -792,6 +817,10 @@ public:
: Superclass(value)
{
}
VTKM_EXEC_CONT Vec(std::initializer_list<T> values)
: Superclass(values)
{
}
template <typename OtherType>
VTKM_EXEC_CONT explicit Vec(const Vec<OtherType, Size>& src)
......@@ -851,6 +880,10 @@ public:
: Superclass(value)
{
}
VTKM_EXEC_CONT Vec(std::initializer_list<T> values)
: Superclass(values)
{
}
template <typename OtherType>
VTKM_EXEC_CONT Vec(const Vec<OtherType, 1>& src)
......@@ -873,6 +906,10 @@ public:
: Superclass(value)
{
}
VTKM_EXEC_CONT Vec(std::initializer_list<T> values)
: Superclass(values)
{
}
template <typename OtherType>
VTKM_EXEC_CONT Vec(const Vec<OtherType, 2>& src)
......@@ -902,6 +939,10 @@ public:
: Superclass(value)
{
}
VTKM_EXEC_CONT Vec(std::initializer_list<T> values)
: Superclass(values)
{
}
template <typename OtherType>
VTKM_EXEC_CONT Vec(const Vec<OtherType, 3>& src)
......@@ -933,6 +974,10 @@ public:
: Superclass(value)
{
}
VTKM_EXEC_CONT Vec(std::initializer_list<T> values)
: Superclass(values)
{
}
template <typename OtherType>
VTKM_EXEC_CONT Vec(const Vec<OtherType, 4>& src)
......@@ -950,28 +995,22 @@ public:
}
};
/// Initializes and returns a Vec of length 2.
/// Initializes and returns a Vec initialized by the given intializer_list. Due to limitations in
/// C++11, you also have to specify the length of the Vec.
///
template <typename T>
VTKM_EXEC_CONT vtkm::Vec<T, 2> make_Vec(const T& x, const T& y)
template <vtkm::IdComponent Size, typename T>
VTKM_EXEC_CONT vtkm::Vec<T, Size> make_Vec(std::initializer_list<T> values)
{
return vtkm::Vec<T, 2>(x, y);
return vtkm::Vec<T, Size>(values);
}
/// Initializes and returns a Vec of length 3.
/// Initializes and returns a Vec containing all the arguments. The arguments should all be the
/// same type or compile issues will occur.
///
template <typename T>
VTKM_EXEC_CONT vtkm::Vec<T, 3> make_Vec(const T& x, const T& y, const T& z)
{
return vtkm::Vec<T, 3>(x, y, z);
}
/// Initializes and returns a Vec of length 4.
///
template <typename T>
VTKM_EXEC_CONT vtkm::Vec<T, 4> make_Vec(const T& x, const T& y, const T& z, const T& w)
template <typename T, typename... Ts>
VTKM_EXEC_CONT vtkm::Vec<T, sizeof...(Ts) + 1> make_Vec(const T& value0, const Ts&... values)
{
return vtkm::Vec<T, 4>(x, y, z, w);
return vtkm::Vec<T, sizeof...(Ts) + 1>({ value0, values... });
}
/// \brief A Vec-like representation for short arrays.
......
......@@ -386,6 +386,15 @@ VTKM_CONT ArrayHandleSwizzle<ArrayHandleType, OutSize> make_ArrayHandleSwizzle(
{
return ArrayHandleSwizzle<ArrayHandleType, OutSize>(array, map);
}
template <typename ArrayHandleType, typename... SwizzleIndexTypes>
VTKM_CONT ArrayHandleSwizzle<ArrayHandleType, sizeof...(SwizzleIndexTypes) + 1>
make_ArrayHandleSwizzle(const ArrayHandleType& array,
vtkm::IdComponent swizzleIndex0,
SwizzleIndexTypes... swizzleIndices)
{
return make_ArrayHandleSwizzle(array, vtkm::make_Vec(swizzleIndex0, swizzleIndices...));
}
}
} // namespace vtkm::cont
......
......@@ -327,7 +327,7 @@ void TestComponentMapValidator()
bool error = false;
try
{
vtkm::cont::make_ArrayHandleSwizzle(dummy, vtkm::make_Vec(0, 1, 2, 1));
vtkm::cont::make_ArrayHandleSwizzle(dummy, 0, 1, 2, 1);
error = true;
}
catch (vtkm::cont::ErrorBadValue& e)
......@@ -338,7 +338,7 @@ void TestComponentMapValidator()
try
{
vtkm::cont::make_ArrayHandleSwizzle(dummy, vtkm::make_Vec(0, 1, 2, -1));
vtkm::cont::make_ArrayHandleSwizzle(dummy, 0, 1, 2, -1);
error = true;
}
catch (vtkm::cont::ErrorBadValue& e)
......@@ -349,7 +349,7 @@ void TestComponentMapValidator()
try
{
vtkm::cont::make_ArrayHandleSwizzle(dummy, vtkm::make_Vec(0, 1, 2, 5));
vtkm::cont::make_ArrayHandleSwizzle(dummy, 0, 1, 2, 5);
error = true;
}
catch (vtkm::cont::ErrorBadValue& e)
......
......@@ -449,10 +449,16 @@ void TypeTest(const vtkm::Vec<Scalar, 2>&)
GeneralVecTypeTest(Vector());
Vector a(2, 4);
Vector b(1, 2);
Vector a{ 2, 4 };
Vector b = { 1, 2 };
Scalar s = 5;
VTKM_TEST_ASSERT(a == vtkm::make_Vec(Scalar(2), Scalar(4)), "make_Vec creates different object.");
VTKM_TEST_ASSERT(a == vtkm::make_Vec<2>({ Scalar(2), Scalar(4) }),
"make_Vec creates different object.");
VTKM_TEST_ASSERT((a == vtkm::Vec<Scalar, 2>{ Scalar(2), Scalar(4) }),
"Construct with initializer list creates different object.");
Vector plus = a + b;
VTKM_TEST_ASSERT(test_equal(plus, vtkm::make_Vec(3, 6)), "Vectors do not add correctly.");
......@@ -510,10 +516,17 @@ void TypeTest(const vtkm::Vec<Scalar, 3>&)
GeneralVecTypeTest(Vector());
Vector a(2, 4, 6);
Vector b(1, 2, 3);
Vector a = { 2, 4, 6 };
Vector b{ 1, 2, 3 };
Scalar s = 5;
VTKM_TEST_ASSERT(a == vtkm::make_Vec(Scalar(2), Scalar(4), Scalar(6)),
"make_Vec creates different object.");
VTKM_TEST_ASSERT(a == vtkm::make_Vec<3>({ Scalar(2), Scalar(4), Scalar(6) }),
"make_Vec creates different object.");
VTKM_TEST_ASSERT((a == vtkm::Vec<Scalar, 3>{ Scalar(2), Scalar(4), Scalar(6) }),
"Construct with initializer list creates different object.");
Vector plus = a + b;
VTKM_TEST_ASSERT(test_equal(plus, vtkm::make_Vec(3, 6, 9)), "Vectors do not add correctly.");
......@@ -572,10 +585,17 @@ void TypeTest(const vtkm::Vec<Scalar, 4>&)
GeneralVecTypeTest(Vector());
Vector a(2, 4, 6, 8);
Vector b(1, 2, 3, 4);
Vector a{ 2, 4, 6, 8 };
Vector b = { 1, 2, 3, 4 };
Scalar s = 5;
VTKM_TEST_ASSERT(a == vtkm::make_Vec(Scalar(2), Scalar(4), Scalar(6), Scalar(8)),
"make_Vec creates different object.");
VTKM_TEST_ASSERT(a == vtkm::make_Vec<4>({ Scalar(2), Scalar(4), Scalar(6), Scalar(8) }),
"make_Vec creates different object.");
VTKM_TEST_ASSERT((a == vtkm::Vec<Scalar, 4>{ Scalar(2), Scalar(4), Scalar(6), Scalar(8) }),
"Construct with initializer list creates different object.");
Vector plus = a + b;
VTKM_TEST_ASSERT(test_equal(plus, vtkm::make_Vec(3, 6, 9, 12)), "Vectors do not add correctly.");
......@@ -685,6 +705,62 @@ void TypeTest(Scalar)
}
}
template <typename Scalar>
void TypeTest(vtkm::Vec<vtkm::Vec<Scalar, 2>, 3>)
{
using Vector = vtkm::Vec<vtkm::Vec<Scalar, 2>, 3>;
{
Vector vec = { { 0, 1 }, { 2, 3 }, { 4, 5 } };
std::cout << "Initialize completely " << vec << std::endl;
VTKM_TEST_ASSERT(test_equal(vec[0][0], 0), "Vec of vec initializer list wrong.");
VTKM_TEST_ASSERT(test_equal(vec[0][1], 1), "Vec of vec initializer list wrong.");
VTKM_TEST_ASSERT(test_equal(vec[1][0], 2), "Vec of vec initializer list wrong.");
VTKM_TEST_ASSERT(test_equal(vec[1][1], 3), "Vec of vec initializer list wrong.");
VTKM_TEST_ASSERT(test_equal(vec[2][0], 4), "Vec of vec initializer list wrong.");
VTKM_TEST_ASSERT(test_equal(vec[2][1], 5), "Vec of vec initializer list wrong.");
}
{
Vector vec = { vtkm::make_Vec(Scalar(0), Scalar(1)) };
std::cout << "Initialize inner " << vec << std::endl;
VTKM_TEST_ASSERT(test_equal(vec[0][0], 0), "Vec of vec initializer list wrong.");
VTKM_TEST_ASSERT(test_equal(vec[0][1], 1), "Vec of vec initializer list wrong.");
VTKM_TEST_ASSERT(test_equal(vec[1][0], 0), "Vec of vec initializer list wrong.");
VTKM_TEST_ASSERT(test_equal(vec[1][1], 1), "Vec of vec initializer list wrong.");
VTKM_TEST_ASSERT(test_equal(vec[2][0], 0), "Vec of vec initializer list wrong.");
VTKM_TEST_ASSERT(test_equal(vec[2][1], 1), "Vec of vec initializer list wrong.");
}
{
Vector vec = { { 0, 1 } };
std::cout << "Initialize inner " << vec << std::endl;
VTKM_TEST_ASSERT(test_equal(vec[0][0], 0), "Vec of vec initializer list wrong.");
VTKM_TEST_ASSERT(test_equal(vec[0][1], 1), "Vec of vec initializer list wrong.");
VTKM_TEST_ASSERT(test_equal(vec[1][0], 0), "Vec of vec initializer list wrong.");
VTKM_TEST_ASSERT(test_equal(vec[1][1], 1), "Vec of vec initializer list wrong.");
VTKM_TEST_ASSERT(test_equal(vec[2][0], 0), "Vec of vec initializer list wrong.");
VTKM_TEST_ASSERT(test_equal(vec[2][1], 1), "Vec of vec initializer list wrong.");
}
{
Vector vec = { { 0 }, { 1 }, { 2 } };
std::cout << "Initialize outer " << vec << std::endl;
VTKM_TEST_ASSERT(test_equal(vec[0][0], 0), "Vec of vec initializer list wrong.");
VTKM_TEST_ASSERT(test_equal(vec[0][1], 0), "Vec of vec initializer list wrong.");
VTKM_TEST_ASSERT(test_equal(vec[1][0], 1), "Vec of vec initializer list wrong.");
VTKM_TEST_ASSERT(test_equal(vec[1][1], 1), "Vec of vec initializer list wrong.");
VTKM_TEST_ASSERT(test_equal(vec[2][0], 2), "Vec of vec initializer list wrong.");
VTKM_TEST_ASSERT(test_equal(vec[2][1], 2), "Vec of vec initializer list wrong.");
}
{
// Both of these constructors are disallowed.
//Vector vec1 = { 0, 1, 2 };
//Vector vec2 = { 0, 1 };
}
}
struct TypeTestFunctor
{
template <typename T>
......@@ -699,7 +775,9 @@ struct TypesToTest : vtkm::ListTagJoin<vtkm::testing::Testing::TypeListTagExempl
vtkm::Vec<vtkm::Id, 4>,
vtkm::Vec<unsigned char, 4>,
vtkm::Vec<vtkm::Id, 1>,
vtkm::Vec<vtkm::Float64, 1>>>
vtkm::Vec<vtkm::Float64, 1>,
vtkm::Vec<vtkm::Id2, 3>,
vtkm::Vec<vtkm::Vec<vtkm::Float32, 2>, 3>>>
{
};
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment