Ensure that Portal::Set isn't defined for read-only portals.

This patch removes (or conditionally removes) the Set method from
portals that are read-only so that IsWritableArrayHandle will work as
expected. The ArrayPortal doxygen has been updated to reflect this.

The remaining exceptions are `ArrayPortalVirtual` and
`ArrayPortalMultiplexer`, since their mutability cannot be determined at
compile time.
This commit is contained in:
Allison Vacanti 2019-09-13 11:42:33 -04:00
parent a6bcd820aa
commit 7e01edb017
12 changed files with 91 additions and 77 deletions

@ -17,6 +17,8 @@
#include <vtkmtaotuple/include/Tuple.h>
#include <vtkm/internal/brigand.hpp>
#include <type_traits>
namespace vtkm
@ -373,11 +375,18 @@ struct ArraySizeValidator
}
};
template <typename PortalList>
using AllPortalsAreWritable =
typename brigand::all<PortalList,
brigand::bind<vtkm::internal::PortalSupportsSets, brigand::_1>>::type;
} // end namespace compvec
template <typename PortalTuple>
class VTKM_ALWAYS_EXPORT ArrayPortalCompositeVector
{
using Writable = compvec::AllPortalsAreWritable<PortalTuple>;
public:
using ValueType = typename compvec::GetValueType<PortalTuple>::ValueType;
@ -459,8 +468,9 @@ public:
return result;
}
VTKM_EXEC_CONT
void Set(vtkm::Id index, const ValueType& value) const
template <typename Writable_ = Writable,
typename = typename std::enable_if<Writable_::value>::type>
VTKM_EXEC_CONT void Set(vtkm::Id index, const ValueType& value) const
{
SetImpl<0, PortalTuple>::Exec(this->Portals, value, index);
}

@ -22,6 +22,10 @@ namespace internal
template <typename PortalType1, typename PortalType2>
class VTKM_ALWAYS_EXPORT ArrayPortalConcatenate
{
using WritableP1 = vtkm::internal::PortalSupportsSets<PortalType1>;
using WritableP2 = vtkm::internal::PortalSupportsSets<PortalType2>;
using Writable = std::integral_constant<bool, WritableP1::value && WritableP2::value>;
public:
using ValueType = typename PortalType1::ValueType;
@ -58,18 +62,27 @@ public:
ValueType Get(vtkm::Id index) const
{
if (index < this->portal1.GetNumberOfValues())
{
return this->portal1.Get(index);
}
else
{
return this->portal2.Get(index - this->portal1.GetNumberOfValues());
}
}
VTKM_EXEC_CONT
void Set(vtkm::Id index, const ValueType& value) const
template <typename Writable_ = Writable,
typename = typename std::enable_if<Writable_::value>::type>
VTKM_EXEC_CONT void Set(vtkm::Id index, const ValueType& value) const
{
if (index < this->portal1.GetNumberOfValues())
{
this->portal1.Set(index, value);
}
else
{
this->portal2.Set(index - this->portal1.GetNumberOfValues(), value);
}
}
VTKM_EXEC_CONT

@ -23,6 +23,8 @@ namespace internal
template <typename PortalType>
class VTKM_ALWAYS_EXPORT ArrayPortalExtractComponent
{
using Writable = vtkm::internal::PortalSupportsSets<PortalType>;
public:
using VectorType = typename PortalType::ValueType;
using Traits = vtkm::VecTraits<VectorType>;
@ -58,8 +60,9 @@ public:
return Traits::GetComponent(this->Portal.Get(index), this->Component);
}
VTKM_EXEC_CONT
void Set(vtkm::Id index, const ValueType& value) const
template <typename Writable_ = Writable,
typename = typename std::enable_if<Writable_::value>::type>
VTKM_EXEC_CONT void Set(vtkm::Id index, const ValueType& value) const
{
VectorType vec = this->Portal.Get(index);
Traits::SetComponent(vec, this->Component, value);

@ -25,6 +25,8 @@ namespace internal
template <typename PortalType, vtkm::IdComponent N_COMPONENTS>
class VTKM_ALWAYS_EXPORT ArrayPortalGroupVec
{
using Writable = vtkm::internal::PortalSupportsSets<PortalType>;
public:
static constexpr vtkm::IdComponent NUM_COMPONENTS = N_COMPONENTS;
using SourcePortalType = PortalType;
@ -79,8 +81,9 @@ public:
}
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC_CONT
void Set(vtkm::Id index, const ValueType& value) const
template <typename Writable_ = Writable,
typename = typename std::enable_if<Writable_::value>::type>
VTKM_EXEC_CONT void Set(vtkm::Id index, const ValueType& value) const
{
vtkm::Id sourceIndex = index * NUM_COMPONENTS;
for (vtkm::IdComponent componentIndex = 0; componentIndex < NUM_COMPONENTS; componentIndex++)

@ -24,6 +24,8 @@ namespace internal
template <typename IndexPortalType, typename ValuePortalType>
class VTKM_ALWAYS_EXPORT ArrayPortalPermutation
{
using Writable = vtkm::internal::PortalSupportsSets<ValuePortalType>;
public:
using ValueType = typename ValuePortalType::ValueType;
@ -69,8 +71,9 @@ public:
}
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC
void Set(vtkm::Id index, const ValueType& value) const
template <typename Writable_ = Writable,
typename = typename std::enable_if<Writable_::value>::type>
VTKM_EXEC void Set(vtkm::Id index, const ValueType& value) const
{
vtkm::Id permutedIndex = this->IndexPortal.Get(index);
this->ValuePortal.Set(permutedIndex, value);

@ -26,6 +26,8 @@ namespace internal
template <typename PortalType>
class VTKM_ALWAYS_EXPORT ArrayPortalReverse
{
using Writable = vtkm::internal::PortalSupportsSets<PortalType>;
public:
using ValueType = typename PortalType::ValueType;
@ -56,8 +58,9 @@ public:
return this->portal.Get(portal.GetNumberOfValues() - index - 1);
}
VTKM_EXEC_CONT
void Set(vtkm::Id index, const ValueType& value) const
template <typename Writable_ = Writable,
typename = typename std::enable_if<Writable_::value>::type>
VTKM_EXEC_CONT void Set(vtkm::Id index, const ValueType& value) const
{
this->portal.Set(portal.GetNumberOfValues() - index - 1, value);
}

@ -23,6 +23,8 @@ namespace internal
template <typename P>
class VTKM_ALWAYS_EXPORT ArrayPortalStreaming
{
using Writable = vtkm::internal::PortalSupportsSets<P>;
public:
using PortalType = P;
using ValueType = typename PortalType::ValueType;
@ -66,8 +68,9 @@ public:
return this->InputPortal.Get(this->BlockIndex * this->BlockSize + index);
}
VTKM_CONT
void Set(vtkm::Id index, const ValueType& value) const
template <typename Writable_ = Writable,
typename = typename std::enable_if<Writable_::value>::type>
VTKM_CONT void Set(vtkm::Id index, const ValueType& value) const
{
this->InputPortal.Set(this->BlockIndex * this->BlockSize + index, value);
}

@ -117,6 +117,7 @@ template <typename PortalType, typename ArrayHandleType, vtkm::IdComponent OutSi
class VTKM_ALWAYS_EXPORT ArrayPortalSwizzle
{
using Traits = internal::ArrayHandleSwizzleTraits<ArrayHandleType, OutSize>;
using Writable = vtkm::internal::PortalSupportsSets<PortalType>;
public:
using MapType = typename Traits::MapType;
@ -154,8 +155,9 @@ public:
return result;
}
VTKM_EXEC_CONT
void Set(vtkm::Id index, const ValueType& value) const
template <typename Writable_ = Writable,
typename = typename std::enable_if<Writable_::value>::type>
VTKM_EXEC_CONT void Set(vtkm::Id index, const ValueType& value) const
{
if (Traits::AllCompsUsed)
{ // No need to prefetch the value, all values overwritten

@ -90,16 +90,6 @@ public:
VTKM_EXEC_CONT
ValueType Get(vtkm::Id index) const { return this->Functor(this->Portal.Get(index)); }
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC_CONT
void Set(vtkm::Id vtkmNotUsed(index), const ValueType& vtkmNotUsed(value)) const
{
#if !(defined(VTKM_MSVC) && defined(VTKM_CUDA))
VTKM_ASSERT(false &&
"Cannot write to read-only transform array. (No inverse transform given.)");
#endif
}
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC_CONT
const PortalType& GetPortal() const { return this->Portal; }
@ -120,6 +110,8 @@ template <typename ValueType_,
class VTKM_ALWAYS_EXPORT ArrayPortalTransform
: public ArrayPortalTransform<ValueType_, PortalType_, FunctorType_, NullFunctorType>
{
using Writable = vtkm::internal::PortalSupportsSets<PortalType_>;
public:
using Superclass = ArrayPortalTransform<ValueType_, PortalType_, FunctorType_, NullFunctorType>;
using PortalType = PortalType_;
@ -147,11 +139,11 @@ public:
}
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC_CONT
void Set(vtkm::Id index, const ValueType& value) const
template <typename Writable_ = Writable,
typename = typename std::enable_if<Writable_::value>::type>
VTKM_EXEC_CONT void Set(vtkm::Id index, const ValueType& value) const
{
using call_supported_t = typename vtkm::internal::PortalSupportsSets<PortalType>::type;
this->Set(call_supported_t(), index, value);
this->Portal.Set(index, this->InverseFunctor(value));
}
VTKM_SUPPRESS_EXEC_WARNINGS
@ -160,14 +152,6 @@ public:
private:
InverseFunctorType InverseFunctor;
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC_CONT
inline void Set(std::true_type, vtkm::Id index, const ValueType& value) const
{
this->Portal.Set(index, this->InverseFunctor(value));
}
VTKM_EXEC_CONT inline void Set(std::false_type, vtkm::Id, const ValueType&) const {}
};
}
}

@ -26,6 +26,8 @@ namespace internal
template <typename TargetPortalType>
class ArrayPortalView
{
using Writable = vtkm::internal::PortalSupportsSets<TargetPortalType>;
public:
using ValueType = typename TargetPortalType::ValueType;
@ -59,8 +61,9 @@ public:
ValueType Get(vtkm::Id index) const { return this->TargetPortal.Get(index + this->StartIndex); }
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC_CONT
void Set(vtkm::Id index, const ValueType& value) const
template <typename Writable_ = Writable,
typename = typename std::enable_if<Writable_::value>::type>
VTKM_EXEC_CONT void Set(vtkm::Id index, const ValueType& value) const
{
this->TargetPortal.Set(index + this->StartIndex, value);
}

@ -26,6 +26,14 @@ namespace internal
template <typename ValueType_, typename PortalTypeFirst_, typename PortalTypeSecond_>
class ArrayPortalZip
{
using ReadableP1 = vtkm::internal::PortalSupportsGets<PortalTypeFirst_>;
using ReadableP2 = vtkm::internal::PortalSupportsGets<PortalTypeSecond_>;
using WritableP1 = vtkm::internal::PortalSupportsSets<PortalTypeFirst_>;
using WritableP2 = vtkm::internal::PortalSupportsSets<PortalTypeSecond_>;
using Readable = std::integral_constant<bool, ReadableP1::value && ReadableP2::value>;
using Writable = std::integral_constant<bool, WritableP1::value && WritableP2::value>;
public:
using ValueType = ValueType_;
using T = typename ValueType::FirstType;
@ -64,23 +72,19 @@ public:
VTKM_EXEC_CONT
vtkm::Id GetNumberOfValues() const { return this->PortalFirst.GetNumberOfValues(); }
VTKM_EXEC
ValueType Get(vtkm::Id index) const
template <typename Readable_ = Readable,
typename = typename std::enable_if<Readable_::value>::type>
VTKM_EXEC_CONT ValueType Get(vtkm::Id index) const noexcept
{
using call_supported_t1 = typename vtkm::internal::PortalSupportsGets<PortalTypeFirst>::type;
using call_supported_t2 = typename vtkm::internal::PortalSupportsGets<PortalTypeSecond>::type;
return vtkm::make_Pair(this->GetFirst(call_supported_t1(), index),
this->GetSecond(call_supported_t2(), index));
return vtkm::make_Pair(this->PortalFirst.Get(index), this->PortalSecond.Get(index));
}
VTKM_EXEC
void Set(vtkm::Id index, const ValueType& value) const
template <typename Writable_ = Writable,
typename = typename std::enable_if<Writable_::value>::type>
VTKM_EXEC_CONT void Set(vtkm::Id index, const ValueType& value) const noexcept
{
using call_supported_t1 = typename vtkm::internal::PortalSupportsSets<PortalTypeFirst>::type;
using call_supported_t2 = typename vtkm::internal::PortalSupportsSets<PortalTypeSecond>::type;
this->SetFirst(call_supported_t1(), index, value.first);
this->SetSecond(call_supported_t2(), index, value.second);
this->PortalFirst.Set(index, value.first);
this->PortalSecond.Set(index, value.second);
}
VTKM_EXEC_CONT
@ -90,28 +94,6 @@ public:
const PortalTypeSecond& GetSecondPortal() const { return this->PortalSecond; }
private:
VTKM_EXEC inline T GetFirst(std::true_type, vtkm::Id index) const noexcept
{
return this->PortalFirst.Get(index);
}
VTKM_EXEC inline T GetFirst(std::false_type, vtkm::Id) const noexcept { return T{}; }
VTKM_EXEC inline U GetSecond(std::true_type, vtkm::Id index) const noexcept
{
return this->PortalSecond.Get(index);
}
VTKM_EXEC inline U GetSecond(std::false_type, vtkm::Id) const noexcept { return U{}; }
VTKM_EXEC inline void SetFirst(std::true_type, vtkm::Id index, const T& value) const noexcept
{
this->PortalFirst.Set(index, value);
}
VTKM_EXEC inline void SetFirst(std::false_type, vtkm::Id, const T&) const noexcept {}
VTKM_EXEC inline void SetSecond(std::true_type, vtkm::Id index, const U& value) const noexcept
{
this->PortalSecond.Set(index, value);
}
VTKM_EXEC inline void SetSecond(std::false_type, vtkm::Id, const U&) const noexcept {}
PortalTypeFirst PortalFirst;
PortalTypeSecond PortalSecond;
};

@ -45,6 +45,12 @@ namespace cont
/// Although portals are defined in the execution environment, they are also
/// used in the control environment for accessing data on the host.
///
/// Since utilities like IsWritableArrayHandle checks for the existence of a Set
/// method on a portal, if the portal is backed by a read-only ArrayHandle, the
/// Set method must not be defined. If the portal may or may not be writable
/// (e.g., ArrayHandleCast may be casting a read-only OR read-write array), the
/// Set method may be conditionally removed using SFINAE.
///
template <typename T>
class ArrayPortal
{
@ -65,8 +71,7 @@ public:
ValueType Get(vtkm::Id index) const;
/// Sets a value in the array. If it is not possible to set a value in the
/// array, this method may error out (for example with a VTKM_ASSERT). In
/// this case the behavior is undefined.
/// array, this method must not be defined.
///
VTKM_EXEC_CONT
void Set(vtkm::Id index, const ValueType& value) const;