Establish `api/` as the home for installed headers.
[alexxy/gromacs.git] / api / legacy / include / gromacs / utility / arrayref.h
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
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.
9  *
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.
14  *
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.
19  *
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.
24  *
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.
32  *
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.
35  */
36 /*! \file
37  * \brief
38  * Declares gmx::ArrayRef
39  *
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>
44  * \inpublicapi
45  * \ingroup module_utility
46  */
47 #ifndef GMX_UTILITY_ARRAYREF_H
48 #define GMX_UTILITY_ARRAYREF_H
49
50 #include <cassert>
51 #include <cstddef>
52
53 #include <array>
54 #include <iterator>
55 #include <stdexcept>
56 #include <utility>
57 #include <vector>
58
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>
63 #endif
64
65 namespace gmx
66 {
67
68 template<class T>
69 struct ArrayRefIter :
70     boost::stl_interfaces::iterator_interface<ArrayRefIter<T>, std::random_access_iterator_tag, T>
71 {
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)
78     {
79     }
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
83     {
84         it_ += i;
85         return *this;
86     }
87     constexpr auto operator-(ArrayRefIter other) const noexcept { return it_ - other.it_; }
88
89 private:
90     T* it_;
91 };
92
93 /*! \brief STL-like interface to a C array of T (or part
94  * of a std container of T).
95  *
96  * \tparam T  Value type of elements.
97  *
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.
107  *
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.
111  *
112  * Methods in this class do not throw, except where indicated.
113  *
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.
116  *
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.
121  *
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.
125  *
126  * \todo
127  * This class is not complete. There are likely also methods missing (not
128  * required for current usage).
129  *
130  * \inpublicapi
131  * \ingroup module_utility
132  */
133 template<typename T>
134 class ArrayRef
135 {
136 public:
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.
152     typedef T* pointer;
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;
159
160     /*! \brief
161      * Constructs an empty reference.
162      */
163     ArrayRef() : begin_(nullptr), end_(nullptr) {}
164     /*! \brief
165      * Constructs a reference to a container or reference
166      *
167      * \param[in] o container to reference.
168      *
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).
172      *
173      * Passed container must remain valid and not be reallocated for the
174      * lifetime of this object.
175      *
176      * This constructor is not explicit to allow directly passing
177      * a container to a method that takes ArrayRef.
178      *
179      * \todo Use std::is_convertible_v when CUDA 11 is a requirement.
180      */
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())
183     {
184     }
185     /*! \brief
186      * Constructs a reference to a particular range.
187      *
188      * \param[in] begin  Pointer to the beginning of a range.
189      * \param[in] end    Pointer to the end of a range.
190      *
191      * Passed pointers must remain valid for the lifetime of this object.
192      */
193     ArrayRef(pointer begin, pointer end) : begin_(begin), end_(end)
194     {
195         assert((end >= begin && "Invalid range"));
196     }
197     /*! \brief
198      * Constructs a reference to a particular range.
199      *
200      * \param[in] begin  Iterator to the beginning of a range.
201      * \param[in] end    iterator to the end of a range.
202      *
203      * Passed iterators must remain valid for the lifetime of this object.
204      */
205     ArrayRef(iterator begin, iterator end) : begin_(begin), end_(end)
206     {
207         assert((end >= begin && "Invalid range"));
208     }
209     //! \cond
210     // Doxygen 1.8.5 doesn't parse the declaration correctly...
211     /*! \brief
212      * Constructs a reference to a C array.
213      *
214      * \param[in] array  C array to reference.
215      * \tparam    count  Deduced number of elements in \p array.
216      *
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.
221      *
222      * Passed array must remain valid for the lifetime of this object.
223      *
224      * This constructor is not explicit to allow directly passing
225      * a C array to a function that takes an ArrayRef parameter.
226      */
227     template<size_t count>
228     ArrayRef(value_type (&array)[count]) : begin_(array), end_(array + count)
229     {
230     }
231     //! \endcond
232
233     //! Returns a reference to part of the memory.
234     ArrayRef subArray(size_type start, size_type count) const
235     {
236         return { begin_ + start, begin_ + start + count };
237     }
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()); }
246
247     /*! \brief Returns the size of the reference.
248      *
249      * \note Use ssize for any expression involving arithmetic operations
250          (including loop indices).
251      */
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_; }
259
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
264     {
265         if (n >= size())
266         {
267             throw std::out_of_range("Vector index out of range");
268         }
269         return begin_[n];
270     }
271     //! Returns the first element.
272     reference front() const { return *(begin_); }
273     //! Returns the first element.
274     reference back() const { return *(end_ - 1); }
275
276     //! Returns a raw pointer to the contents of the array.
277     pointer data() const { return begin_.data(); }
278
279     /*! \brief
280      * Swaps referenced memory with the other object.
281      *
282      * The actual memory areas are not modified, only the references are
283      * swapped.
284      */
285     void swap(ArrayRef<T>& other)
286     {
287         std::swap(begin_, other.begin_);
288         std::swap(end_, other.end_);
289     }
290
291 private:
292     iterator begin_;
293     iterator end_;
294 };
295
296 /*! \brief
297  * Constructs a reference to a C array.
298  *
299  * \param[in] begin  Pointer to the beginning of array.
300  * \param[in] size   Number of elements in array.
301  *
302  * Passed array must remain valid for the lifetime of this object.
303  */
304 //! \related ArrayRef
305 template<typename T>
306 ArrayRef<T> arrayRefFromArray(T* begin, size_t size)
307 {
308     return ArrayRef<T>(begin, begin + size);
309 }
310
311 //! \copydoc arrayRefFromArray
312 //! \related ArrayRef
313 template<typename T>
314 ArrayRef<const T> constArrayRefFromArray(const T* begin, size_t size)
315 {
316     return ArrayRef<const T>(begin, begin + size);
317 }
318
319 /*! \brief
320  * Create ArrayRef from container with type deduction
321  *
322  * \see ArrayRef
323  *
324  * \todo Use std::is_const_v when CUDA 11 is a requirement.
325  */
326 template<typename T>
327 ArrayRef<std::conditional_t<std::is_const<T>::value, const typename T::value_type, typename T::value_type>>
328 makeArrayRef(T& c)
329 {
330     return c;
331 }
332
333 /*! \brief
334  * Create ArrayRef to const T from container with type deduction
335  *
336  * \see ArrayRef
337  */
338 template<typename T>
339 ArrayRef<const typename T::value_type> makeConstArrayRef(const T& c)
340 {
341     return c;
342 }
343
344 /*! \brief
345  * Simple swap method for ArrayRef objects.
346  *
347  * \see ArrayRef::swap()
348  *
349  * \ingroup module_utility
350  */
351 template<typename T>
352 void swap(ArrayRef<T>& a, ArrayRef<T>& b)
353 {
354     a.swap(b);
355 }
356
357 /*! \brief Return a vector that is a copy of an ArrayRef.
358  *
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
362  *
363  *   auto v = copyOf(arrayRef);
364  *
365  * \ingroup module_utility
366  */
367 template<typename T>
368 std::vector<T> copyOf(const ArrayRef<const T>& arrayRef)
369 {
370     return std::vector<T>(arrayRef.begin(), arrayRef.end());
371 }
372
373 } // namespace gmx
374
375 #endif