2 * This file is part of the GROMACS molecular simulation package.
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.
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.
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.
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.
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.
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.
37 * \brief Defines helper types for class enumerations.
39 * These helper types facilitate iterating over class enums, and
40 * maintaining a type-safe and value-safe matching list of names. The
41 * code is closely based on the public-domain code by Guilherme
42 * R. Lampert, found in commit c94c18a of
43 * https://github.com/glampert/enum_helpers/blob/master/enum_helpers.hpp
46 * NOTE This functionality only works for enumerations of monotonically
47 * increasing values, starting with the value zero.
57 * EnumerationWrapper<Foo> iter;
61 * // 'c' is a constant from Foo
64 * const EnumerationArray<Foo, std::string> fooStrings = { { "Bar", "Baz", "Fooz" } };
66 * for (Foo c : keysOf(fooStrings))
68 * print(fooStrings[c]);
71 * ArrayRef<const std::string> namesRef(fooStrings);
73 * \author Mark Abraham <mark.j.abraham@gmail.com>
75 * \ingroup module_utility
77 #ifndef GMX_UTILITY_ENUMHELPERS_H
78 #define GMX_UTILITY_ENUMHELPERS_H
83 #include <type_traits>
85 #include "gromacs/utility/gmxassert.h"
91 * \brief Allows iterating sequential enumerators.
93 * You can also provide an increment step > 1 if each constant is
94 * spaced by a larger value. Terminating constant is assumed to be a
95 * 'Count' member, which is never iterated. A different name for the
96 * terminating constant can also be specified on declaration.
98 * NOTE This functionality only works for enumerations of monotonically
99 * increasing values, starting with the value zero.
101 * See file documentation for usage example.
103 * \tparam EnumType The enum (class) type.
104 * \tparam Last Last constant or number thereof (assumes a default 'Count' member).
105 * \tparam Step Step increment.
110 EnumType Last = EnumType::Count,
111 unsigned int Step = 1
113 class EnumerationIterator final
116 //! Convenience alias
117 using IntegerType = typename std::underlying_type<EnumType>::type;
119 /*! \name Iterator type traits
120 * Satisfies the requirements for STL forward iterator.
123 using iterator_category = std::forward_iterator_tag;
124 using value_type = EnumType;
125 using difference_type = std::ptrdiff_t;
126 using pointer = EnumType*;
127 using reference = EnumType&;
130 constexpr EnumerationIterator() noexcept :
131 m_current { 0 } // Assumes 0 is the first constant
134 constexpr EnumerationIterator(const EnumType index) noexcept
135 : m_current(static_cast<IntegerType>(index))
137 //! Pre-increment operator
138 EnumerationIterator operator++()
143 //! Post-increment operator
144 EnumerationIterator operator++(int)
146 EnumerationIterator old_val { *this };
150 //! Dereference operator
151 EnumType operator*() const
153 GMX_ASSERT(m_current < static_cast<IntegerType>(Last), "dereferencing out of range");
154 return static_cast<EnumType>(m_current);
158 //! Comparision operators
159 bool operator== (const EnumerationIterator other) const noexcept { return m_current == other.m_current; }
160 bool operator!= (const EnumerationIterator other) const noexcept { return m_current != other.m_current; }
161 bool operator< (const EnumerationIterator other) const noexcept { return m_current < other.m_current; }
162 bool operator> (const EnumerationIterator other) const noexcept { return m_current > other.m_current; }
163 bool operator<= (const EnumerationIterator other) const noexcept { return m_current <= other.m_current; }
164 bool operator>= (const EnumerationIterator other) const noexcept { return m_current >= other.m_current; }
168 IntegerType m_current;
172 * \brief Allows constructing iterators for looping over sequential enumerators.
174 * These are particularly useful for range-based for statements.
176 * You can also provide an increment step > 1 if each constant is
177 * spaced by a larger value. Terminating constant is assumed to be a
178 * 'Count' member, which is never iterated. A different name for the
179 * terminating constant can also be specified on declaration.
181 * See file documentation for usage example.
183 * \tparam EnumType The enum (class) type.
184 * \tparam Last Last constant or number thereof (assumes a default 'Count' member).
185 * \tparam Step Step increment.
190 EnumType Last = EnumType::Count,
191 unsigned int Step = 1
193 class EnumerationWrapper final
196 //! Convenience alias.
197 using IteratorType = EnumerationIterator<EnumType, Last, Step>;
199 //! Functions required for range-based for statements to work.
201 IteratorType begin() const { return IteratorType {}; }
202 IteratorType end() const { return IteratorType { Last }; }
207 * \brief Wrapper for a C-style array with size and indexing defined
208 * by an enum. Useful for declaring arrays of enum names for debug
209 * or other printing. An ArrayRef<DataType> may be constructed from
210 * an object of this type.
212 * See file documentation for usage example.
214 * \tparam EnumType The enum (class) type.
215 * \tparam DataType Type of the data stored in the array.
216 * \tparam ArraySize Size in entries of the array.
220 typename EnumType, // The enum (class) type.
221 typename DataType, // Type of the data stored in the array.
222 EnumType ArraySize = EnumType::Count // Size in entries of the array.
224 struct EnumerationArray final
226 //! Convenience alias
227 using EnumerationWrapperType = EnumerationWrapper<EnumType, ArraySize>;
229 /*! \brief Data for names.
231 * Data is kept public so we can use direct aggregate
232 * initialization just like in a plain C-style array. */
233 DataType m_elements[std::size_t(ArraySize)];
235 //! Returns an object that provides iterators over the keys.
236 static constexpr EnumerationWrapperType keys() { return EnumerationWrapperType {}; }
237 //! Returns the size of the enumeration.
238 static constexpr std::size_t size() { return std::size_t(ArraySize); }
241 //! Array access with asserts:
242 DataType &operator[](const std::size_t index)
244 GMX_ASSERT(index < size(), "index out of range");
245 return m_elements[index];
247 const DataType &operator[](const std::size_t index) const
249 GMX_ASSERT(index < size(), "index out of range");
250 return m_elements[index];
253 DataType &operator[](const EnumType index)
255 GMX_ASSERT(std::size_t(index) < size(), "index out of range");
256 return m_elements[std::size_t(index)];
258 const DataType &operator[](const EnumType index) const
260 GMX_ASSERT(std::size_t(index) < size(), "index out of range");
261 return m_elements[std::size_t(index)];
266 //! Range iterators (unchecked)
267 using iterator = DataType *;
268 using const_iterator = const DataType *;
269 using reverse_iterator = std::reverse_iterator<iterator>;
270 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
274 //! Getters for forward iterators for ranges
275 iterator begin() { return &m_elements[0]; }
276 iterator end() { return &m_elements[size()]; }
277 const_iterator begin() const { return &m_elements[0]; }
278 const_iterator end() const { return &m_elements[size()]; }
282 //! Getters for reverse iterators for ranges
283 reverse_iterator rbegin() { return reverse_iterator { end() }; }
284 reverse_iterator rend() { return reverse_iterator { begin() }; }
285 const_reverse_iterator rbegin() const { return const_reverse_iterator { end() }; }
286 const_reverse_iterator rend() const { return const_reverse_iterator { begin() }; }
290 //! Pointers (unchecked)
291 using pointer = DataType *;
292 using const_pointer = const DataType *;
295 //! Returns a const raw pointer to the contents of the array.
296 const_pointer data() const { return &m_elements[0]; }
299 /*! \brief Returns an object that provides iterators over the keys
300 * associated with \c EnumerationArrayType.
302 * This helper function is useful in contexts where there is an object
303 * of an EnumerationArray, and we want to use a range-based for loop
304 * over the keys associated with it, and it would be inconvenient to
305 * use the very word EnumerationArray<...> type, nor introduce a using
306 * statement for this purpose. It is legal in C++ to call a static
307 * member function (such as keys()) via an object rather than the
308 * type, but clang-tidy warns about that. So instead we make available
309 * a free function that calls that static method. */
310 template <typename EnumerationArrayType>
311 typename EnumerationArrayType::EnumerationWrapperType keysOf(const EnumerationArrayType & /* arrayObject */)
313 return EnumerationArrayType::keys();