1 /* 2 * This file is part of the GROMACS molecular simulation package. 3 * 4 * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by 5 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl, 6 * and including many others, as listed in the AUTHORS file in the 7 * top-level source directory and at http://www.gromacs.org. 8 * 9 * GROMACS is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU Lesser General Public License 11 * as published by the Free Software Foundation; either version 2.1 12 * of the License, or (at your option) any later version. 13 * 14 * GROMACS is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * Lesser General Public License for more details. 18 * 19 * You should have received a copy of the GNU Lesser General Public 20 * License along with GROMACS; if not, see 21 * http://www.gnu.org/licenses, or write to the Free Software Foundation, 22 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 23 * 24 * If you want to redistribute modifications to GROMACS, please 25 * consider that scientific software is very special. Version 26 * control is crucial - bugs must be traceable. We will be happy to 27 * consider code for inclusion in the official distribution, but 28 * derived work must not be called official GROMACS. Details are found 29 * in the README & COPYING files - if they are missing, get the 30 * official version at http://www.gromacs.org. 31 * 32 * To help us fund GROMACS development, we humbly ask that you cite 33 * the research papers on the package. Check out http://www.gromacs.org. 34 */ 35 /*! \file 36 * \brief Declares gmx::ArrayRefWithPadding that refers to memory whose 37 * size includes padding for SIMD operations. 38 * 39 * \author Mark Abraham <mark.j.abraham@gmail.com> 40 * 41 * \inpublicapi 42 * \ingroup module_math 43 */ 44 #ifndef GMX_MATH_ARRAYREFWITHPADDING_H 45 #define GMX_MATH_ARRAYREFWITHPADDING_H 46 47 #include <cstddef> 48 49 #include "gromacs/utility/arrayref.h" 50 #include "gromacs/utility/basedefinitions.h" 51 #include "gromacs/utility/gmxassert.h" 52 53 namespace gmx 54 { 55 56 /*! \brief Interface to a C array of T (or part of a std container of 57 * T), that includes padding that is suitable for the kinds of SIMD 58 * operations GROMACS uses. 59 * 60 * High level code e.g. in the force calculation routines need to hold 61 * a non-owning view of memory and be able to create ArrayRef objects 62 * that view padded or unpadded memory, suitable for the various 63 * component routines. This class implements that non-owning view, 64 * and the only available functionality refers to its size, and the 65 * methods to create such ArrayRef objects. 66 * 67 * \copydoc ArrayRef 68 * \inlibraryapi 69 * \ingroup module_math 70 */ 71 template<typename T> 72 class ArrayRefWithPadding 73 { 74 public: 75 //! Type of values stored in the reference. 76 using value_type = T; 77 //! Type for representing size of the reference. 78 using size_type = index; 79 //! Const pointer to an element. 80 using const_pointer = const T*; 81 //! Const iterator type to an element. 82 using const_iterator = const T*; 83 //! Pointer to an element. 84 using pointer = T*; 85 //! Iterator type to an element. 86 using iterator = T*; 87 88 /*! \brief 89 * Constructs an empty reference. 90 */ ArrayRefWithPadding()91 ArrayRefWithPadding() : begin_(nullptr), end_(nullptr), paddedEnd_(nullptr) {} 92 /*! \brief 93 * Constructs a reference to a particular range. 94 * 95 * \param[in] begin Pointer to the beginning of a range. 96 * \param[in] end Pointer to the end of a range without padding. 97 * \param[in] paddedEnd Pointer to the end of a range including padding. 98 * 99 * Passed pointers must remain valid for the lifetime of this object. 100 */ ArrayRefWithPadding(pointer begin,pointer end,pointer paddedEnd)101 ArrayRefWithPadding(pointer begin, pointer end, pointer paddedEnd) : 102 begin_(begin), 103 end_(end), 104 paddedEnd_(paddedEnd) 105 { 106 GMX_ASSERT(end >= begin, "Invalid range"); 107 GMX_ASSERT(paddedEnd >= end, "Invalid range"); 108 } 109 //! Copy constructor ArrayRefWithPadding(const ArrayRefWithPadding & o)110 ArrayRefWithPadding(const ArrayRefWithPadding& o) : 111 begin_(o.begin_), 112 end_(o.end_), 113 paddedEnd_(o.paddedEnd_) 114 { 115 } 116 //! Move constructor ArrayRefWithPadding(ArrayRefWithPadding && o)117 ArrayRefWithPadding(ArrayRefWithPadding&& o) noexcept : 118 begin_(std::move(o.begin_)), 119 end_(std::move(o.end_)), 120 paddedEnd_(std::move(o.paddedEnd_)) 121 { 122 } 123 /*! \brief Convenience overload constructor to make an ArrayRefWithPadding<const T> from a non-const one. 124 * 125 * \todo Use std::is_same_v when CUDA 11 is a requirement. 126 */ 127 template<typename U, typename = std::enable_if_t<std::is_same<value_type, const typename std::remove_reference_t<U>::value_type>::value>> ArrayRefWithPadding(U && o)128 ArrayRefWithPadding(U&& o) 129 { 130 auto constArrayRefWithPadding = o.constArrayRefWithPadding(); 131 this->swap(constArrayRefWithPadding); 132 } 133 //! Copy assignment operator 134 ArrayRefWithPadding& operator=(ArrayRefWithPadding const& o) 135 { 136 if (&o != this) 137 { 138 begin_ = o.begin_; 139 end_ = o.end_; 140 paddedEnd_ = o.paddedEnd_; 141 } 142 return *this; 143 } 144 //! Move assignment operator 145 ArrayRefWithPadding& operator=(ArrayRefWithPadding&& o) noexcept 146 { 147 if (&o != this) 148 { 149 begin_ = std::move(o.begin_); 150 end_ = std::move(o.end_); 151 paddedEnd_ = std::move(o.paddedEnd_); 152 } 153 return *this; 154 } 155 156 //! Return the size of the view, i.e with the padding. size()157 size_type size() const { return paddedEnd_ - begin_; } 158 //! Whether the reference refers to no memory. empty()159 bool empty() const { return begin_ == end_; } 160 161 //! Returns an ArrayRef of elements that does not include the padding region. unpaddedArrayRef()162 ArrayRef<T> unpaddedArrayRef() { return { begin_, end_ }; } 163 //! Returns an ArrayRef of const elements that does not include the padding region. unpaddedConstArrayRef()164 ArrayRef<const T> unpaddedConstArrayRef() const { return { begin_, end_ }; } 165 //! Returns an ArrayRef of elements that does include the padding region. paddedArrayRef()166 ArrayRef<T> paddedArrayRef() { return { begin_, paddedEnd_ }; } 167 //! Returns an ArrayRef of const elements that does include the padding region. paddedConstArrayRef()168 ArrayRef<const T> paddedConstArrayRef() const { return { begin_, paddedEnd_ }; } 169 //! Returns an identical ArrayRefWithPadding that refers to const elements. constArrayRefWithPadding()170 ArrayRefWithPadding<const T> constArrayRefWithPadding() const 171 { 172 return { begin_, end_, paddedEnd_ }; 173 } 174 /*! \brief 175 * Swaps referenced memory with the other object. 176 * 177 * The actual memory areas are not modified, only the references are 178 * swapped. 179 */ swap(ArrayRefWithPadding<T> & other)180 void swap(ArrayRefWithPadding<T>& other) 181 { 182 std::swap(begin_, other.begin_); 183 std::swap(end_, other.end_); 184 std::swap(paddedEnd_, other.paddedEnd_); 185 } 186 187 private: 188 pointer begin_; 189 pointer end_; 190 pointer paddedEnd_; 191 }; 192 193 } // namespace gmx 194 195 #endif 196