Split lines with many copyright years
[alexxy/gromacs.git] / src / 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 <cstddef>
51
52 #include <array>
53 #include <iterator>
54 #include <stdexcept>
55 #include <utility>
56 #include <vector>
57
58 #include "gromacs/utility/gmxassert.h"
59
60 namespace gmx
61 {
62
63 /*! \brief STL-like interface to a C array of T (or part
64  * of a std container of T).
65  *
66  * \tparam T  Value type of elements.
67  *
68  * This class provides an interface similar to \c std::vector<T, A>, with the
69  * following main differences:
70  *  - This class does not have its own storage.  Instead, it references an
71  *    existing array of values (either a C-style array or part of an existing
72  *    std::vector<T, A> or std::array<T>).
73  *  - It is only possible to modify the values themselves through ArrayRef;
74  *    it is not possible to add or remove values.
75  *  - Copying objects of this type is cheap, and the copies behave identically
76  *    to the original object: the copy references the same set of values.
77  *
78  * This class is useful for writing wrappers that expose a view of the
79  * internal data stored as a single vector/array, which can be a whole
80  * or part of the underlying storage.
81  *
82  * Methods in this class do not throw, except where indicated.
83  *
84  * Note that due to a Doxygen limitation, the constructor that takes a C array
85  * whose size is known at compile time does not appear in the documentation.
86  *
87  * To refer to const data of type T, ArrayRef<const T> is used. For both const
88  * and non-const std::vector and std::array an ArrayRef view can be created.
89  * Attempting to create a non-const ArrayRef of a const vector/array will result
90  * in a compiler error in the respective constructor.
91  *
92  * For SIMD types there is template specialization available
93  * (e.g. ArrayRef<SimdReal>) in gromacs/simd/simd_memory.h which should have
94  * the same functionality as much as possible.
95  *
96  * \todo
97  * This class is not complete. There are likely also methods missing (not
98  * required for current usage).
99  *
100  * \inpublicapi
101  * \ingroup module_utility
102  */
103 template<typename T>
104 class ArrayRef
105 {
106 public:
107     //! Type of values stored in the reference.
108     typedef T value_type;
109     //! Type for representing size of the reference.
110     typedef size_t size_type;
111     //! Type for representing difference between two indices.
112     typedef ptrdiff_t difference_type;
113     //! Const reference to an element.
114     typedef const T& const_reference;
115     //! Const pointer to an element.
116     typedef const T* const_pointer;
117     //! Const iterator type to an element.
118     typedef const T* const_iterator;
119     //! Reference to an element.
120     typedef T& reference;
121     //! Pointer to an element.
122     typedef T* pointer;
123     //! Iterator type to an element.
124     typedef T* iterator;
125     //! Standard reverse iterator.
126     typedef std::reverse_iterator<iterator> reverse_iterator;
127     //! Standard reverse iterator.
128     typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
129
130     /*! \brief
131      * Constructs an empty reference.
132      */
133     ArrayRef() : begin_(nullptr), end_(nullptr) {}
134     /*! \brief
135      * Constructs a reference to a container or reference
136      *
137      * \param[in] o container to reference.
138      *
139      * Can be used to create a reference to a whole vector, std::array or
140      * an ArrayRef. The destination has to have a convertible pointer type
141      * (identical besides const or base class).
142      *
143      * Passed container must remain valid and not be reallocated for the
144      * lifetime of this object.
145      *
146      * This constructor is not explicit to allow directly passing
147      * a container to a method that takes ArrayRef.
148      */
149     template<typename U, typename = std::enable_if_t<std::is_convertible<typename std::remove_reference_t<U>::pointer, pointer>::value>>
150     ArrayRef(U&& o) : begin_(o.data()), end_(o.data() + o.size())
151     {
152     }
153     /*! \brief
154      * Constructs a reference to a particular range.
155      *
156      * \param[in] begin  Pointer to the beginning of a range.
157      * \param[in] end    Pointer to the end of a range.
158      *
159      * Passed pointers must remain valid for the lifetime of this object.
160      */
161     ArrayRef(pointer begin, pointer end) : begin_(begin), end_(end)
162     {
163         GMX_ASSERT(end >= begin, "Invalid range");
164     }
165     //! \cond
166     // Doxygen 1.8.5 doesn't parse the declaration correctly...
167     /*! \brief
168      * Constructs a reference to a C array.
169      *
170      * \param[in] array  C array to reference.
171      * \tparam    count  Deduced number of elements in \p array.
172      *
173      * This constructor can only be used with a real array (not with a
174      * pointer).  It constructs a reference to the whole array, without
175      * a need to pass the number of elements explicitly.  The compiler
176      * must be able to deduce the array size.
177      *
178      * Passed array must remain valid for the lifetime of this object.
179      *
180      * This constructor is not explicit to allow directly passing
181      * a C array to a function that takes an ArrayRef parameter.
182      */
183     template<size_t count>
184     ArrayRef(value_type (&array)[count]) : begin_(array), end_(array + count)
185     {
186     }
187     //! \endcond
188
189     //! Returns a reference to part of the memory.
190     ArrayRef subArray(size_type start, size_type count) const
191     {
192         return { begin_ + start, begin_ + start + count };
193     }
194     //! Returns an iterator to the beginning of the reference.
195     iterator begin() const { return begin_; }
196     //! Returns an iterator to the end of the reference.
197     iterator end() const { return end_; }
198     //! Returns an iterator to the reverse beginning of the reference.
199     reverse_iterator rbegin() const { return reverse_iterator(end()); }
200     //! Returns an iterator to the reverse end of the reference.
201     reverse_iterator rend() const { return reverse_iterator(begin()); }
202
203     /*! \brief Returns the size of the reference.
204      *
205      * \note Use ssize for any expression involving arithmetic operations
206          (including loop indices).
207      */
208     size_type size() const { return end_ - begin_; }
209     //! Returns the signed size of the reference.
210     index ssize() const { return size(); }
211     //! Identical to size().
212     size_type capacity() const { return end_ - begin_; }
213     //! Whether the reference refers to no memory.
214     bool empty() const { return begin_ == end_; }
215
216     //! Access an element.
217     reference operator[](size_type n) const { return begin_[n]; }
218     //! Access an element (throws on out-of-range error).
219     reference at(size_type n) const
220     {
221         if (n >= size())
222         {
223             throw std::out_of_range("Vector index out of range");
224         }
225         return begin_[n];
226     }
227     //! Returns the first element.
228     reference front() const { return *begin_; }
229     //! Returns the first element.
230     reference back() const { return *(end_ - 1); }
231
232     //! Returns a raw pointer to the contents of the array.
233     pointer data() const { return begin_; }
234
235     /*! \brief
236      * Swaps referenced memory with the other object.
237      *
238      * The actual memory areas are not modified, only the references are
239      * swapped.
240      */
241     void swap(ArrayRef<T>& other)
242     {
243         std::swap(begin_, other.begin_);
244         std::swap(end_, other.end_);
245     }
246
247 private:
248     pointer begin_;
249     pointer end_;
250 };
251
252 //! \copydoc ArrayRef::fromArray()
253 //! \related ArrayRef
254 template<typename T>
255 ArrayRef<T> arrayRefFromArray(T* begin, size_t size)
256 {
257     return ArrayRef<T>(begin, begin + size);
258 }
259
260 //! \copydoc ArrayRef::fromArray()
261 //! \related ArrayRef
262 template<typename T>
263 ArrayRef<const T> constArrayRefFromArray(const T* begin, size_t size)
264 {
265     return ArrayRef<const T>(begin, begin + size);
266 }
267
268 /*! \brief
269  * Create ArrayRef from container with type deduction
270  *
271  * \see ArrayRef
272  */
273 template<typename T>
274 ArrayRef<std::conditional_t<std::is_const<T>::value, const typename T::value_type, typename T::value_type>>
275 makeArrayRef(T& c)
276 {
277     return c;
278 }
279
280 /*! \brief
281  * Create ArrayRef to const T from container with type deduction
282  *
283  * \see ArrayRef
284  */
285 template<typename T>
286 ArrayRef<const typename T::value_type> makeConstArrayRef(const T& c)
287 {
288     return c;
289 }
290
291 /*! \brief
292  * Simple swap method for ArrayRef objects.
293  *
294  * \see ArrayRef::swap()
295  *
296  * \ingroup module_utility
297  */
298 template<typename T>
299 void swap(ArrayRef<T>& a, ArrayRef<T>& b)
300 {
301     a.swap(b);
302 }
303
304 /*! \brief Return a vector that is a copy of an ArrayRef.
305  *
306  * This makes it convenient, clear, and performant (the compiler will
307  * either do RVO to elide the temporary, or invoke the move constructor
308  * taking the unnamed temporary) to write a declaration like
309  *
310  *   auto v = copyOf(arrayRef);
311  *
312  * \ingroup module_utility
313  */
314 template<typename T>
315 std::vector<T> copyOf(const ArrayRef<const T>& arrayRef)
316 {
317     return std::vector<T>(arrayRef.begin(), arrayRef.end());
318 }
319
320 } // namespace gmx
321
322 #endif