2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
5 * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
6 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
7 * and including many others, as listed in the AUTHORS file in the
8 * top-level source directory and at http://www.gromacs.org.
10 * GROMACS is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public License
12 * as published by the Free Software Foundation; either version 2.1
13 * of the License, or (at your option) any later version.
15 * GROMACS is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with GROMACS; if not, see
22 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
23 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 * If you want to redistribute modifications to GROMACS, please
26 * consider that scientific software is very special. Version
27 * control is crucial - bugs must be traceable. We will be happy to
28 * consider code for inclusion in the official distribution, but
29 * derived work must not be called official GROMACS. Details are found
30 * in the README & COPYING files - if they are missing, get the
31 * official version at http://www.gromacs.org.
33 * To help us fund GROMACS development, we humbly ask that you cite
34 * the research papers on the package. Check out http://www.gromacs.org.
38 * Declares gmx::ArrayRef
40 * \author Teemu Murtola <teemu.murtola@gmail.com>
41 * \author Mark Abraham <mark.j.abraham@gmail.com>
42 * \author Roland Schulz <roland.schulz@intel.com>
43 * \author Berk Hess <hess@kth.se>
45 * \ingroup module_utility
47 #ifndef GMX_UTILITY_ARRAYREF_H
48 #define GMX_UTILITY_ARRAYREF_H
59 #if __has_include(<boost/stl_interfaces/iterator_interface.hpp>)
60 # include <boost/stl_interfaces/iterator_interface.hpp>
61 #else // fallback for installed headers
62 # include <gromacs/external/boost/stl_interfaces/iterator_interface.hpp>
70 boost::stl_interfaces::iterator_interface<ArrayRefIter<T>, std::random_access_iterator_tag, T>
72 // This default constructor does not initialize it_
73 constexpr ArrayRefIter() noexcept {}
74 constexpr explicit ArrayRefIter(T* it) noexcept : it_(it) {}
75 // TODO: Use std::is_const_v when CUDA 11 is a requirement.
76 template<class T2 = T, class = std::enable_if_t<std::is_const<T2>::value>>
77 constexpr ArrayRefIter(ArrayRefIter<std::remove_const_t<T2>> it) noexcept : it_(&*it)
80 constexpr T* data() const noexcept { return it_; }
81 constexpr T& operator*() const noexcept { return *it_; }
82 constexpr ArrayRefIter& operator+=(std::ptrdiff_t i) noexcept
87 constexpr auto operator-(ArrayRefIter other) const noexcept { return it_ - other.it_; }
93 /*! \brief STL-like interface to a C array of T (or part
94 * of a std container of T).
96 * \tparam T Value type of elements.
98 * This class provides an interface similar to \c std::vector<T, A>, with the
99 * following main differences:
100 * - This class does not have its own storage. Instead, it references an
101 * existing array of values (either a C-style array or part of an existing
102 * std::vector<T, A> or std::array<T>).
103 * - It is only possible to modify the values themselves through ArrayRef;
104 * it is not possible to add or remove values.
105 * - Copying objects of this type is cheap, and the copies behave identically
106 * to the original object: the copy references the same set of values.
108 * This class is useful for writing wrappers that expose a view of the
109 * internal data stored as a single vector/array, which can be a whole
110 * or part of the underlying storage.
112 * Methods in this class do not throw, except where indicated.
114 * Note that due to a Doxygen limitation, the constructor that takes a C array
115 * whose size is known at compile time does not appear in the documentation.
117 * To refer to const data of type T, ArrayRef<const T> is used. For both const
118 * and non-const std::vector and std::array an ArrayRef view can be created.
119 * Attempting to create a non-const ArrayRef of a const vector/array will result
120 * in a compiler error in the respective constructor.
122 * For SIMD types there is template specialization available
123 * (e.g. ArrayRef<SimdReal>) in gromacs/simd/simd_memory.h which should have
124 * the same functionality as much as possible.
127 * This class is not complete. There are likely also methods missing (not
128 * required for current usage).
131 * \ingroup module_utility
137 //! Type of values stored in the reference.
138 typedef T value_type;
139 //! Type for representing size of the reference.
140 typedef size_t size_type;
141 //! Type for representing difference between two indices.
142 typedef ptrdiff_t difference_type;
143 //! Const reference to an element.
144 typedef const T& const_reference;
145 //! Const pointer to an element.
146 typedef const T* const_pointer;
147 //! Const iterator type to an element.
148 typedef ArrayRefIter<const T> const_iterator;
149 //! Reference to an element.
150 typedef T& reference;
151 //! Pointer to an element.
153 //! Iterator type to an element.
154 typedef ArrayRefIter<T> iterator;
155 //! Standard reverse iterator.
156 typedef std::reverse_iterator<iterator> reverse_iterator;
157 //! Standard reverse iterator.
158 typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
161 * Constructs an empty reference.
163 ArrayRef() : begin_(nullptr), end_(nullptr) {}
165 * Constructs a reference to a container or reference
167 * \param[in] o container to reference.
169 * Can be used to create a reference to a whole vector, std::array or
170 * an ArrayRef. The destination has to have a convertible pointer type
171 * (identical besides const or base class).
173 * Passed container must remain valid and not be reallocated for the
174 * lifetime of this object.
176 * This constructor is not explicit to allow directly passing
177 * a container to a method that takes ArrayRef.
179 * \todo Use std::is_convertible_v when CUDA 11 is a requirement.
181 template<typename U, typename = std::enable_if_t<std::is_convertible<typename std::remove_reference_t<U>::pointer, pointer>::value>>
182 ArrayRef(U&& o) : begin_(o.data()), end_(o.data() + o.size())
186 * Constructs a reference to a particular range.
188 * \param[in] begin Pointer to the beginning of a range.
189 * \param[in] end Pointer to the end of a range.
191 * Passed pointers must remain valid for the lifetime of this object.
193 ArrayRef(pointer begin, pointer end) : begin_(begin), end_(end)
195 assert((end >= begin && "Invalid range"));
198 * Constructs a reference to a particular range.
200 * \param[in] begin Iterator to the beginning of a range.
201 * \param[in] end iterator to the end of a range.
203 * Passed iterators must remain valid for the lifetime of this object.
205 ArrayRef(iterator begin, iterator end) : begin_(begin), end_(end)
207 assert((end >= begin && "Invalid range"));
210 // Doxygen 1.8.5 doesn't parse the declaration correctly...
212 * Constructs a reference to a C array.
214 * \param[in] array C array to reference.
215 * \tparam count Deduced number of elements in \p array.
217 * This constructor can only be used with a real array (not with a
218 * pointer). It constructs a reference to the whole array, without
219 * a need to pass the number of elements explicitly. The compiler
220 * must be able to deduce the array size.
222 * Passed array must remain valid for the lifetime of this object.
224 * This constructor is not explicit to allow directly passing
225 * a C array to a function that takes an ArrayRef parameter.
227 template<size_t count>
228 ArrayRef(value_type (&array)[count]) : begin_(array), end_(array + count)
233 //! Returns a reference to part of the memory.
234 ArrayRef subArray(size_type start, size_type count) const
236 return { begin_ + start, begin_ + start + count };
238 //! Returns an iterator to the beginning of the reference.
239 iterator begin() const { return iterator(begin_); }
240 //! Returns an iterator to the end of the reference.
241 iterator end() const { return iterator(end_); }
242 //! Returns an iterator to the reverse beginning of the reference.
243 reverse_iterator rbegin() const { return reverse_iterator(end()); }
244 //! Returns an iterator to the reverse end of the reference.
245 reverse_iterator rend() const { return reverse_iterator(begin()); }
247 /*! \brief Returns the size of the reference.
249 * \note Use ssize for any expression involving arithmetic operations
250 (including loop indices).
252 size_type size() const { return end_ - begin_; }
253 //! Returns the signed size of the reference.
254 difference_type ssize() const { return size(); }
255 //! Identical to size().
256 size_type capacity() const { return end_ - begin_; }
257 //! Whether the reference refers to no memory.
258 bool empty() const { return begin_ == end_; }
260 //! Access an element.
261 reference operator[](size_type n) const { return begin_[n]; }
262 //! Access an element (throws on out-of-range error).
263 reference at(size_type n) const
267 throw std::out_of_range("Vector index out of range");
271 //! Returns the first element.
272 reference front() const { return *(begin_); }
273 //! Returns the first element.
274 reference back() const { return *(end_ - 1); }
276 //! Returns a raw pointer to the contents of the array.
277 pointer data() const { return begin_.data(); }
280 * Swaps referenced memory with the other object.
282 * The actual memory areas are not modified, only the references are
285 void swap(ArrayRef<T>& other)
287 std::swap(begin_, other.begin_);
288 std::swap(end_, other.end_);
297 * Constructs a reference to a C array.
299 * \param[in] begin Pointer to the beginning of array.
300 * \param[in] size Number of elements in array.
302 * Passed array must remain valid for the lifetime of this object.
304 //! \related ArrayRef
306 ArrayRef<T> arrayRefFromArray(T* begin, size_t size)
308 return ArrayRef<T>(begin, begin + size);
311 //! \copydoc arrayRefFromArray
312 //! \related ArrayRef
314 ArrayRef<const T> constArrayRefFromArray(const T* begin, size_t size)
316 return ArrayRef<const T>(begin, begin + size);
320 * Create ArrayRef from container with type deduction
324 * \todo Use std::is_const_v when CUDA 11 is a requirement.
327 ArrayRef<std::conditional_t<std::is_const<T>::value, const typename T::value_type, typename T::value_type>>
334 * Create ArrayRef to const T from container with type deduction
339 ArrayRef<const typename T::value_type> makeConstArrayRef(const T& c)
345 * Simple swap method for ArrayRef objects.
347 * \see ArrayRef::swap()
349 * \ingroup module_utility
352 void swap(ArrayRef<T>& a, ArrayRef<T>& b)
357 /*! \brief Return a vector that is a copy of an ArrayRef.
359 * This makes it convenient, clear, and performant (the compiler will
360 * either do RVO to elide the temporary, or invoke the move constructor
361 * taking the unnamed temporary) to write a declaration like
363 * auto v = copyOf(arrayRef);
365 * \ingroup module_utility
368 std::vector<T> copyOf(const ArrayRef<const T>& arrayRef)
370 return std::vector<T>(arrayRef.begin(), arrayRef.end());