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.
36 * \brief Defines helper types for class enumerations.
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
45 * NOTE This functionality only works for enumerations of monotonically
46 * increasing values, starting with the value zero.
56 * EnumerationWrapper<Foo> iter;
60 * // 'c' is a constant from Foo
63 * const EnumerationArray<Foo, std::string> fooStrings = { { "Bar", "Baz", "Fooz" } };
65 * for (Foo c : keysOf(fooStrings))
67 * print(fooStrings[c]);
70 * ArrayRef<const std::string> namesRef(fooStrings);
72 * \author Mark Abraham <mark.j.abraham@gmail.com>
74 * \ingroup module_utility
76 #ifndef GMX_UTILITY_ENUMHELPERS_H
77 #define GMX_UTILITY_ENUMHELPERS_H
82 #include <type_traits>
84 #include "gromacs/utility/gmxassert.h"
90 * \brief Allows iterating sequential enumerators.
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.
97 * NOTE This functionality only works for enumerations of monotonically
98 * increasing values, starting with the value zero.
100 * See file documentation for usage example.
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.
109 EnumType Last
= EnumType::Count
,
110 unsigned int Step
= 1
112 class EnumerationIterator final
115 //! Convenience alias
116 using IntegerType
= std::underlying_type_t
<EnumType
>;
118 /*! \name Iterator type traits
119 * Satisfies the requirements for STL forward iterator.
122 using iterator_category
= std::forward_iterator_tag
;
123 using value_type
= EnumType
;
124 using difference_type
= std::ptrdiff_t;
125 using pointer
= EnumType
*;
126 using reference
= EnumType
&;
129 constexpr EnumerationIterator() noexcept
:
130 m_current
{ 0 } // Assumes 0 is the first constant
133 constexpr EnumerationIterator(const EnumType index
) noexcept
134 : m_current(static_cast<IntegerType
>(index
))
136 //! Pre-increment operator
137 EnumerationIterator
operator++()
142 //! Post-increment operator
143 EnumerationIterator
operator++(int)
145 EnumerationIterator old_val
{ *this };
149 //! Dereference operator
150 EnumType
operator*() const
152 GMX_ASSERT(m_current
< static_cast<IntegerType
>(Last
), "dereferencing out of range");
153 return static_cast<EnumType
>(m_current
);
157 //! Comparision operators
158 bool operator== (const EnumerationIterator other
) const noexcept
{ return m_current
== other
.m_current
; }
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
; }
167 IntegerType m_current
;
171 * \brief Allows constructing iterators for looping over sequential enumerators.
173 * These are particularly useful for range-based for statements.
175 * You can also provide an increment step > 1 if each constant is
176 * spaced by a larger value. Terminating constant is assumed to be a
177 * 'Count' member, which is never iterated. A different name for the
178 * terminating constant can also be specified on declaration.
180 * See file documentation for usage example.
182 * \tparam EnumType The enum (class) type.
183 * \tparam Last Last constant or number thereof (assumes a default 'Count' member).
184 * \tparam Step Step increment.
189 EnumType Last
= EnumType::Count
,
190 unsigned int Step
= 1
192 class EnumerationWrapper final
195 //! Convenience alias.
196 using IteratorType
= EnumerationIterator
<EnumType
, Last
, Step
>;
198 //! Functions required for range-based for statements to work.
200 IteratorType
begin() const { return IteratorType
{}; }
201 IteratorType
end() const { return IteratorType
{ Last
}; }
206 * \brief Wrapper for a C-style array with size and indexing defined
207 * by an enum. Useful for declaring arrays of enum names for debug
208 * or other printing. An ArrayRef<DataType> may be constructed from
209 * an object of this type.
211 * See file documentation for usage example.
213 * \tparam EnumType The enum (class) type.
214 * \tparam DataType Type of the data stored in the array.
215 * \tparam ArraySize Size in entries of the array.
219 typename EnumType
, // The enum (class) type.
220 typename DataType
, // Type of the data stored in the array.
221 EnumType ArraySize
= EnumType::Count
// Size in entries of the array.
223 struct EnumerationArray final
225 //! Convenience alias
226 using EnumerationWrapperType
= EnumerationWrapper
<EnumType
, ArraySize
>;
228 /*! \brief Data for names.
230 * Data is kept public so we can use direct aggregate
231 * initialization just like in a plain C-style array. */
232 DataType m_elements
[std::size_t(ArraySize
)];
234 //! Returns an object that provides iterators over the keys.
235 static constexpr EnumerationWrapperType
keys() { return EnumerationWrapperType
{}; }
236 //! Returns the size of the enumeration.
237 static constexpr std::size_t size() { return std::size_t(ArraySize
); }
240 //! Array access with asserts:
241 DataType
&operator[](const std::size_t index
)
243 GMX_ASSERT(index
< size(), "index out of range");
244 return m_elements
[index
];
246 const DataType
&operator[](const std::size_t index
) const
248 GMX_ASSERT(index
< size(), "index out of range");
249 return m_elements
[index
];
252 DataType
&operator[](const EnumType index
)
254 GMX_ASSERT(std::size_t(index
) < size(), "index out of range");
255 return m_elements
[std::size_t(index
)];
257 const DataType
&operator[](const EnumType index
) const
259 GMX_ASSERT(std::size_t(index
) < size(), "index out of range");
260 return m_elements
[std::size_t(index
)];
265 //! Range iterators (unchecked)
266 using iterator
= DataType
*;
267 using const_iterator
= const DataType
*;
268 using reverse_iterator
= std::reverse_iterator
<iterator
>;
269 using const_reverse_iterator
= std::reverse_iterator
<const_iterator
>;
273 //! Getters for forward iterators for ranges
274 iterator
begin() { return &m_elements
[0]; }
275 iterator
end() { return &m_elements
[size()]; }
276 const_iterator
begin() const { return &m_elements
[0]; }
277 const_iterator
end() const { return &m_elements
[size()]; }
281 //! Getters for reverse iterators for ranges
282 reverse_iterator
rbegin() { return reverse_iterator
{ end() }; }
283 reverse_iterator
rend() { return reverse_iterator
{ begin() }; }
284 const_reverse_iterator
rbegin() const { return const_reverse_iterator
{ end() }; }
285 const_reverse_iterator
rend() const { return const_reverse_iterator
{ begin() }; }
289 //! Pointers (unchecked)
290 using pointer
= DataType
*;
291 using const_pointer
= const DataType
*;
294 //! Returns a const raw pointer to the contents of the array.
295 const_pointer
data() const { return &m_elements
[0]; }
296 //! Returns a raw pointer to the contents of the array.
297 pointer
data() { return &m_elements
[0]; }
300 /*! \brief Returns an object that provides iterators over the keys
301 * associated with \c EnumerationArrayType.
303 * This helper function is useful in contexts where there is an object
304 * of an EnumerationArray, and we want to use a range-based for loop
305 * over the keys associated with it, and it would be inconvenient to
306 * use the very word EnumerationArray<...> type, nor introduce a using
307 * statement for this purpose. It is legal in C++ to call a static
308 * member function (such as keys()) via an object rather than the
309 * type, but clang-tidy warns about that. So instead we make available
310 * a free function that calls that static method. */
311 template <typename EnumerationArrayType
>
312 typename
EnumerationArrayType::EnumerationWrapperType
keysOf(const EnumerationArrayType
& /* arrayObject */)
314 return EnumerationArrayType::keys();