Forward declare ArrayRef more and inlcude basedefinitions where needed
[alexxy/gromacs.git] / src / gromacs / utility / fixedcapacityvector.h
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2019,2020,2021, 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
37  * Declares gmx::FixedCapacityVector
38  *
39  * \author Berk Hess <hess@kth.se>
40  * \inpublicapi
41  * \ingroup module_utility
42  */
43 #ifndef GMX_UTILITY_FIXEDCAPACITYVECTOR_H
44 #define GMX_UTILITY_FIXEDCAPACITYVECTOR_H
45
46 #include <array>
47 #include <stdexcept>
48
49 #include "gromacs/utility/basedefinitions.h"
50 #include "gromacs/utility/gmxassert.h"
51
52 namespace gmx
53 {
54
55 /*! \brief Vector that behaves likes std::vector but has fixed capacity.
56  *
57  * \tparam T         Value type of elements.
58  * \tparam capacity  The maximum number of elements that can be stored.
59  *
60  * This class provides a variable size container, but with constant
61  * memory usage and can be allocated on the stack and avoid the overhead
62  * of dynamic allocation. This is especially useful for small vectors
63  * which are set up frequently.
64  *
65  * The class supports all methods from \p std::array, but behaves more
66  * like \p std::vector since it has variable size. In addition to the methods
67  * from std::array, from \p std::vector the methods \p push_back(), \p pop_back(),
68  * emplace_back() and \p clear() are supported. In particular, methods that
69  * requires reordering, such as \p insert() and \p emplace() are not
70  * supported to keep the code simple.
71  *
72  * The size is 0 at construction and elements can only be added with
73  * \p push_back() and \p emplace_back().
74  *
75  * \note This class is very similar to the fixed_capacity_vector class
76  * proposed for the C++ standard in document P0843r see:
77  * http://open-std.org/JTC1/SC22/WG21/docs/papers/2018/p0843r1.html
78  *
79  * \inpublicapi
80  * \ingroup module_utility
81  */
82 template<typename T, size_t capacity>
83 class FixedCapacityVector
84 {
85 public:
86     //! Type of values stored in the vector
87     using value_type = T;
88     //! Type for representing size of the vector
89     using size_type = size_t;
90     //! Type for representing difference between two indices
91     using difference_type = ptrdiff_t;
92     //! Const reference to an element
93     using const_reference = const T&;
94     //! Const pointer to an element
95     using const_pointer = const T*;
96     //! Const iterator type to an element
97     using const_iterator = const T*;
98     //! Reference to an element
99     using reference = T&;
100     //! Pointer to an element
101     using pointer = T*;
102     //! Iterator type to an element
103     using iterator = T*;
104     //! Standard reverse iterator
105     using reverse_iterator = std::reverse_iterator<iterator>;
106     //! Standard reverse iterator
107     using const_reverse_iterator = std::reverse_iterator<const_iterator>;
108
109     //! Returns a const iterator to the beginning
110     const_iterator begin() const noexcept { return data(); }
111     //! Returns an iterator to the beginning
112     iterator begin() noexcept { return data(); }
113     //! Returns a const iterator to the end
114     const_iterator end() const noexcept { return end_; }
115     //! Returns an iterator to the end
116     iterator end() noexcept { return end_; }
117     //! Returns a const iterator to the reverse beginning
118     const_reverse_iterator rbegin() const noexcept { return reverse_iterator(end_); }
119     //! Returns an iterator to the reverse beginning
120     reverse_iterator rbegin() noexcept { return reverse_iterator(end_); }
121     //! Returns a const iterator to the reverse end
122     const_reverse_iterator rend() const noexcept { return reverse_iterator(begin()); }
123     //! Returns an iterator to the reverse end
124     reverse_iterator rend() noexcept { return reverse_iterator(begin()); }
125
126     /*! \brief Returns the size
127      *
128      * \note Use ssize for any expression involving arithmetic operations
129          (including loop indices).
130      */
131     size_type size() const noexcept { return end_ - data(); }
132     //! Returns the signed size
133     index ssize() const noexcept { return end_ - data(); }
134     //! Returns whether the vector is empty
135     bool empty() const noexcept { return data() == end_; }
136
137     //! Const access an element
138     const_reference operator[](size_type n) const noexcept
139     {
140         GMX_ASSERT(n < size(), "Index should be in range");
141         return data_[n];
142     }
143     //! Access an element
144     reference operator[](size_type n) noexcept
145     {
146         GMX_ASSERT(n < size(), "Index should be in range");
147         return data_[n];
148     }
149     //! Const access an element, throws an out_of_range exception when out of range
150     const_reference at(size_type n) const
151     {
152         if (n >= size())
153         {
154             throw std::out_of_range("Vector index out of range");
155         }
156         return data_[n];
157     }
158     //! Access an element, throws an out_of_range exception when out of range
159     reference at(size_type n)
160     {
161         if (n >= size())
162         {
163             throw std::out_of_range("Vector index out of range");
164         }
165         return data_[n];
166     }
167     //! Returns the first element
168     reference front() const noexcept { return data_.front(); }
169     //! Returns the last element
170     reference back() const noexcept { return *(end_ - 1); }
171
172     //! Returns a raw pointer to the contents of the array
173     const T* data() const noexcept { return data_.data(); }
174
175     //! Returns a raw pointer to the contents of the array
176     T* data() noexcept { return data_.data(); }
177
178     //! Adds element at the end
179     void push_back(const T& value) noexcept
180     {
181         GMX_ASSERT(size() < capacity, "Cannot add more elements than the capacity");
182         *end_ = value;
183         end_++;
184     }
185
186     //! Deletes last element
187     void pop_back() noexcept
188     {
189         GMX_ASSERT(!empty(), "Can only delete last element when present");
190         end_--;
191     }
192
193     //! Constructs an element at the end
194     template<class... Args>
195     reference emplace_back(Args&&... args)
196     {
197         GMX_ASSERT(size() < capacity, "Cannot add more elements than the capacity");
198         if (std::is_move_assignable<T>::value)
199         {
200             *end_ = std::move(T(args...));
201         }
202         else
203         {
204             *end_ = T(args...);
205         }
206         end_++;
207
208         return back();
209     }
210
211     //! Clears content
212     void clear() noexcept { end_ = data(); }
213
214 private:
215     //! The elements, stored in a fixed size array
216     std::array<T, capacity> data_;
217     //! The size of the vector
218     pointer end_ = data();
219 };
220
221 } // namespace gmx
222
223 #endif