//============================================================================ // 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. // // Copyright 2014 Sandia Corporation. // Copyright 2014 UT-Battelle, LLC. // Copyright 2014 Los Alamos National Security. // // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, // the U.S. Government retains certain rights in this software. // // Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National // Laboratory (LANL), the U.S. Government retains certain rights in // this software. //============================================================================ #ifndef vtk_m_cont_internal_IteratorFromArrayPortal_h #define vtk_m_cont_internal_IteratorFromArrayPortal_h #include #include VTKM_THIRDPARTY_PRE_INCLUDE #include VTKM_THIRDPARTY_POST_INCLUDE namespace vtkm { namespace cont { namespace internal { namespace detail { template struct IteratorFromArrayPortalValue { typedef typename ArrayPortalType::ValueType ValueType; VTKM_CONT_EXPORT IteratorFromArrayPortalValue(const ArrayPortalType &portal, vtkm::Id index) : Portal(portal), Index(index) { } VTKM_CONT_EXPORT void Swap( IteratorFromArrayPortalValue &rhs ) throw() { //we need use the explicit type not a proxy temp object //A proxy temp object would point to the same underlying data structure //and would not hold the old value of *this once *this was set to rhs. const ValueType aValue = *this; *this = rhs; rhs = aValue; } VTKM_CONT_EXPORT IteratorFromArrayPortalValue &operator=( const IteratorFromArrayPortalValue &rhs) { this->Portal.Set(this->Index, rhs.Portal.Get(rhs.Index)); return *this; } VTKM_CONT_EXPORT ValueType operator=(const ValueType& value) { this->Portal.Set(this->Index, value); return value; } VTKM_CONT_EXPORT operator ValueType(void) const { return this->Portal.Get(this->Index); } const ArrayPortalType& Portal; vtkm::Id Index; }; } // namespace detail template class IteratorFromArrayPortal : public boost::iterator_facade< IteratorFromArrayPortal, typename ArrayPortalType::ValueType, boost::random_access_traversal_tag, detail::IteratorFromArrayPortalValue > { typedef boost::iterator_facade< IteratorFromArrayPortal, typename ArrayPortalType::ValueType, boost::random_access_traversal_tag, detail::IteratorFromArrayPortalValue > Superclass; public: VTKM_CONT_EXPORT IteratorFromArrayPortal() : Portal(), Index(0) { } VTKM_CONT_EXPORT explicit IteratorFromArrayPortal(const ArrayPortalType &portal, vtkm::Id index = 0) : Portal(portal), Index(index) { } VTKM_CONT_EXPORT detail::IteratorFromArrayPortalValue operator[](std::ptrdiff_t idx) const //NEEDS to be signed { return detail::IteratorFromArrayPortalValue(this->Portal, this->Index + static_cast(idx) ); } private: ArrayPortalType Portal; vtkm::Id Index; // Implementation for boost iterator_facade friend class boost::iterator_core_access; VTKM_CONT_EXPORT detail::IteratorFromArrayPortalValue dereference() const { return detail::IteratorFromArrayPortalValue(this->Portal, this->Index); } VTKM_CONT_EXPORT bool equal(const IteratorFromArrayPortal &other) const { // Technically, we should probably check that the portals are the same, // but the portal interface does not specify an equal operator. It is // by its nature undefined what happens when comparing iterators from // different portals anyway. return (this->Index == other.Index); } VTKM_CONT_EXPORT void increment() { this->Index++; VTKM_ASSERT(this->Index >= 0); VTKM_ASSERT(this->Index <= this->Portal.GetNumberOfValues()); } VTKM_CONT_EXPORT void decrement() { this->Index--; VTKM_ASSERT(this->Index >= 0); VTKM_ASSERT(this->Index <= this->Portal.GetNumberOfValues()); } VTKM_CONT_EXPORT void advance(typename Superclass::difference_type delta) { this->Index += static_cast(delta); VTKM_ASSERT(this->Index >= 0); VTKM_ASSERT(this->Index <= this->Portal.GetNumberOfValues()); } VTKM_CONT_EXPORT typename Superclass::difference_type distance_to(const IteratorFromArrayPortal &other) const { // Technically, we should probably check that the portals are the same, // but the portal interface does not specify an equal operator. It is // by its nature undefined what happens when comparing iterators from // different portals anyway. return static_cast::difference_type>( other.Index - this->Index); } }; template IteratorFromArrayPortal make_IteratorBegin( const ArrayPortalType &portal) { return IteratorFromArrayPortal(portal, 0); } template IteratorFromArrayPortal make_IteratorEnd( const ArrayPortalType &portal) { return IteratorFromArrayPortal(portal, portal.GetNumberOfValues()); } //implementat a custom swap function, since the std::swap won't work //since we return RValues instead of Lvalues template void swap( vtkm::cont::internal::detail::IteratorFromArrayPortalValue a, vtkm::cont::internal::detail::IteratorFromArrayPortalValue b) { a.Swap(b); } } } } // namespace vtkm::cont::internal namespace boost { /// The boost::iterator_facade lets you redefine the reference type, which is /// good since you cannot set an array portal from a reference in general. /// However, the iterator_facade then checks to see if the reference type is an /// actual reference, and if it is not it can set up some rather restrictive /// traits that we do not want. To get around this, specialize the /// boost::is_reference type check to declare our value class as a reference /// type. Even though it is not a true reference type, its operators make it /// behave like one. /// template struct is_reference< vtkm::cont::internal::detail::IteratorFromArrayPortalValue > : public boost::true_type { }; } // namespace boost #endif //vtk_m_cont_internal_IteratorFromArrayPortal_h