Apply clang-format to source tree
[alexxy/gromacs.git] / src / gromacs / utility / enumerationhelpers.h
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2019, 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 Defines helper types for class enumerations.
37  *
38  * These helper types facilitate iterating over class enums, and
39  * maintaining a type-safe and value-safe matching list of names. The
40  * code is closely based on the public-domain code by Guilherme
41  * R. Lampert, found in commit c94c18a of
42  * https://github.com/glampert/enum_helpers/blob/master/enum_helpers.hpp
43  * Thanks Guilherme!
44  *
45  * NOTE This functionality only works for enumerations of monotonically
46  * increasing values, starting with the value zero.
47  *
48  * Usage examples:
49  *
50  *  enum class Foo
51  *  {
52  *      Bar, Baz, Fooz,
53  *      Count
54  *  };
55  *
56  *  EnumerationWrapper<Foo> iter;
57  *
58  *  for (Foo c : iter)
59  *  {
60  *      // 'c' is a constant from Foo
61  *  }
62  *
63  *  const EnumerationArray<Foo, std::string> fooStrings = { { "Bar", "Baz", "Fooz" } };
64  *
65  *  for (Foo c : keysOf(fooStrings))
66  *  {
67  *      print(fooStrings[c]);
68  *  }
69  *
70  *  ArrayRef<const std::string> namesRef(fooStrings);
71  *
72  * \author Mark Abraham <mark.j.abraham@gmail.com>
73  * \inlibraryapi
74  * \ingroup module_utility
75  */
76 #ifndef GMX_UTILITY_ENUMHELPERS_H
77 #define GMX_UTILITY_ENUMHELPERS_H
78
79 #include <cstddef>
80
81 #include <iterator>
82 #include <type_traits>
83
84 #include "gromacs/utility/gmxassert.h"
85
86 namespace gmx
87 {
88
89 /*! \libinternal
90  * \brief Allows iterating sequential enumerators.
91  *
92  * You can also provide an increment step > 1 if each constant is
93  * spaced by a larger value.  Terminating constant is assumed to be a
94  * 'Count' member, which is never iterated. A different name for the
95  * terminating constant can also be specified on declaration.
96  *
97  * NOTE This functionality only works for enumerations of monotonically
98  * increasing values, starting with the value zero.
99  *
100  * See file documentation for usage example.
101  *
102  * \tparam  EnumType   The enum (class) type.
103  * \tparam  Last       Last constant or number thereof (assumes a default 'Count' member).
104  * \tparam  Step       Step increment.
105  */
106 template<typename EnumType, EnumType Last = EnumType::Count, unsigned int Step = 1>
107 class EnumerationIterator final
108 {
109 public:
110     //! Convenience alias
111     using IntegerType = std::underlying_type_t<EnumType>;
112
113     /*! \name Iterator type traits
114      * Satisfies the requirements for STL forward iterator.
115      * \{
116      */
117     using iterator_category = std::forward_iterator_tag;
118     using value_type        = EnumType;
119     using difference_type   = std::ptrdiff_t;
120     using pointer           = EnumType*;
121     using reference         = EnumType&;
122     //! \}
123
124     constexpr EnumerationIterator() noexcept : m_current{ 0 } // Assumes 0 is the first constant
125     {
126     }
127     //! Copy constructor
128     constexpr EnumerationIterator(const EnumType index) noexcept :
129         m_current(static_cast<IntegerType>(index))
130     {
131     }
132     //! Pre-increment operator
133     EnumerationIterator operator++()
134     {
135         m_current += Step;
136         return *this;
137     }
138     //! Post-increment operator
139     EnumerationIterator operator++(int)
140     {
141         EnumerationIterator old_val{ *this };
142         m_current += Step;
143         return old_val;
144     }
145     //! Dereference operator
146     EnumType operator*() const
147     {
148         GMX_ASSERT(m_current < static_cast<IntegerType>(Last), "dereferencing out of range");
149         return static_cast<EnumType>(m_current);
150     }
151
152     /*!@{*/
153     //! Comparision operators
154     bool operator==(const EnumerationIterator other) const noexcept
155     {
156         return m_current == other.m_current;
157     }
158     bool operator!=(const EnumerationIterator other) const noexcept
159     {
160         return m_current != other.m_current;
161     }
162     bool operator<(const EnumerationIterator other) const noexcept
163     {
164         return m_current < other.m_current;
165     }
166     bool operator>(const EnumerationIterator other) const noexcept
167     {
168         return m_current > other.m_current;
169     }
170     bool operator<=(const EnumerationIterator other) const noexcept
171     {
172         return m_current <= other.m_current;
173     }
174     bool operator>=(const EnumerationIterator other) const noexcept
175     {
176         return m_current >= other.m_current;
177     }
178     /*!@}*/
179
180 private:
181     IntegerType m_current;
182 };
183
184 /*! \libinternal
185  * \brief Allows constructing iterators for looping over sequential enumerators.
186  *
187  * These are particularly useful for range-based for statements.
188  *
189  * You can also provide an increment step > 1 if each constant is
190  * spaced by a larger value.  Terminating constant is assumed to be a
191  * 'Count' member, which is never iterated. A different name for the
192  * terminating constant can also be specified on declaration.
193  *
194  * See file documentation for usage example.
195  *
196  * \tparam  EnumType   The enum (class) type.
197  * \tparam  Last       Last constant or number thereof (assumes a default 'Count' member).
198  * \tparam  Step       Step increment.
199  */
200 template<typename EnumType, EnumType Last = EnumType::Count, unsigned int Step = 1>
201 class EnumerationWrapper final
202 {
203 public:
204     //! Convenience alias.
205     using IteratorType = EnumerationIterator<EnumType, Last, Step>;
206
207     //! Functions required for range-based for statements to work.
208     /*!@{*/
209     IteratorType begin() const { return IteratorType{}; }
210     IteratorType end() const { return IteratorType{ Last }; }
211     /*!@}*/
212 };
213
214 /*! \libinternal
215  * \brief Wrapper for a C-style array with size and indexing defined
216  * by an enum. Useful for declaring arrays of enum names for debug
217  * or other printing. An ArrayRef<DataType> may be constructed from
218  * an object of this type.
219  *
220  * See file documentation for usage example.
221  *
222  * \tparam  EnumType   The enum (class) type.
223  * \tparam  DataType   Type of the data stored in the array.
224  * \tparam  ArraySize  Size in entries of the array.
225  */
226 template<typename EnumType,                   // The enum (class) type.
227          typename DataType,                   // Type of the data stored in the array.
228          EnumType ArraySize = EnumType::Count // Size in entries of the array.
229          >
230 struct EnumerationArray final
231 {
232     //! Convenience alias
233     using EnumerationWrapperType = EnumerationWrapper<EnumType, ArraySize>;
234
235     /*! \brief Data for names.
236      *
237      * Data is kept public so we can use direct aggregate
238      * initialization just like in a plain C-style array. */
239     DataType m_elements[std::size_t(ArraySize)];
240
241     //! Returns an object that provides iterators over the keys.
242     static constexpr EnumerationWrapperType keys() { return EnumerationWrapperType{}; }
243     //! Returns the size of the enumeration.
244     static constexpr std::size_t size() { return std::size_t(ArraySize); }
245
246     /*!@{*/
247     //! Array access with asserts:
248     DataType& operator[](const std::size_t index)
249     {
250         GMX_ASSERT(index < size(), "index out of range");
251         return m_elements[index];
252     }
253     const DataType& operator[](const std::size_t index) const
254     {
255         GMX_ASSERT(index < size(), "index out of range");
256         return m_elements[index];
257     }
258
259     DataType& operator[](const EnumType index)
260     {
261         GMX_ASSERT(std::size_t(index) < size(), "index out of range");
262         return m_elements[std::size_t(index)];
263     }
264     const DataType& operator[](const EnumType index) const
265     {
266         GMX_ASSERT(std::size_t(index) < size(), "index out of range");
267         return m_elements[std::size_t(index)];
268     }
269     /*!@}*/
270
271     /*!@{*/
272     //! Range iterators (unchecked)
273     using iterator               = DataType*;
274     using const_iterator         = const DataType*;
275     using reverse_iterator       = std::reverse_iterator<iterator>;
276     using const_reverse_iterator = std::reverse_iterator<const_iterator>;
277     /*!@}*/
278
279     /*!@{*/
280     //! Getters for forward iterators for ranges
281     iterator       begin() { return &m_elements[0]; }
282     iterator       end() { return &m_elements[size()]; }
283     const_iterator begin() const { return &m_elements[0]; }
284     const_iterator end() const { return &m_elements[size()]; }
285     /*!@}*/
286
287     /*!@{*/
288     //! Getters for reverse iterators for ranges
289     reverse_iterator       rbegin() { return reverse_iterator{ end() }; }
290     reverse_iterator       rend() { return reverse_iterator{ begin() }; }
291     const_reverse_iterator rbegin() const { return const_reverse_iterator{ end() }; }
292     const_reverse_iterator rend() const { return const_reverse_iterator{ begin() }; }
293     /*!@}*/
294
295     /*!@{*/
296     //! Pointers (unchecked)
297     using pointer       = DataType*;
298     using const_pointer = const DataType*;
299     /*!@}*/
300
301     //! Returns a const raw pointer to the contents of the array.
302     const_pointer data() const { return &m_elements[0]; }
303     //! Returns a raw pointer to the contents of the array.
304     pointer data() { return &m_elements[0]; }
305 };
306
307 /*! \brief Returns an object that provides iterators over the keys
308  * associated with \c EnumerationArrayType.
309  *
310  * This helper function is useful in contexts where there is an object
311  * of an EnumerationArray, and we want to use a range-based for loop
312  * over the keys associated with it, and it would be inconvenient to
313  * use the very word EnumerationArray<...> type, nor introduce a using
314  * statement for this purpose. It is legal in C++ to call a static
315  * member function (such as keys()) via an object rather than the
316  * type, but clang-tidy warns about that. So instead we make available
317  * a free function that calls that static method. */
318 template<typename EnumerationArrayType>
319 typename EnumerationArrayType::EnumerationWrapperType keysOf(const EnumerationArrayType& /* arrayObject */)
320 {
321     return EnumerationArrayType::keys();
322 }
323
324 } // namespace gmx
325
326 #endif