ALib C++ Library
Library Version: 2412 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
iterable.hpp
Go to the documentation of this file.
1//==================================================================================================
2/// \file
3/// This header file is part of module \alib_enums of the \aliblong.
4///
5/// \emoji :copyright: 2013-2024 A-Worx GmbH, Germany.
6/// Published under \ref mainpage_license "Boost Software License".
7//==================================================================================================
8#ifndef HPP_ALIB_ENUMS_ITERABLE
9#define HPP_ALIB_ENUMS_ITERABLE 1
10#pragma once
12
14
15#include "alib/enums/underlyingintegral.hpp"
16#include <cstdint>
17#include <iterator>
18
19namespace alib { namespace enums {
20
21// #################################################################################################
22// struct T_EnumIsIterable
23// #################################################################################################
24
25
26//==================================================================================================
27/// Simple TMP struct that - if specialized - enables standard and range-based C++ iteration of the
28/// elements of an enumeration.
29/// Specializations have to declare <c>constexpr</c> fields #Begin and #End, as documented with this
30/// type.
31///
32/// \note
33/// The unspecialized version of this struct is empty.
34///
35/// If specialized, the following entities become available:
36/// - \alib{enums::iterable;operator+}
37/// - \alib{enums::iterable;operator-}
38/// - struct \alib{enums;EnumIterator}
39///
40/// \attention
41/// Likewise with the operators introduced with other TMP structs of this module,
42/// this documentation "fakes" the operators into namespace
43/// <c>alib::enums::iterable</c>, while in fact they are defined in the global
44/// namespace!<br>
45/// See \ref alib_enums_arithmetic_standard "corresponding note" in the Programmer's Manual
46/// for details.
47///
48/// <b>Restrictions</b><br>
49/// For technical reasons, this concept is not applicable to enum types that are defined as
50/// \c private or \c protected inner types of structs or classes.
51///
52/// \see
53/// - Macros \ref ALIB_ENUMS_MAKE_ITERABLE and \ref ALIB_ENUMS_MAKE_ITERABLE_BEGIN_END, which
54/// specialize this TMP struct for a given enumeration type.
55/// - Type \alib{enums;EnumIterator} used to perform iterations.
56/// - For details and a source code sample see chapter \ref alib_enums_iter "3. Enum Iteration"
57/// of the Programmer's Manual of module \alib_enums.
58///
59/// @tparam TEnum The enum type to enable iteration for.
60/// @tparam TEnableIf This parameter has a default expressions and <b>must not</b> be provided
61/// with specializations of this struct.
62/// It is used to ensure that template parameter \p{TEnum} is an enumeration type.
63//==================================================================================================
64template<typename TEnum,
65 typename TEnableIf= typename std::enable_if<std::is_enum<TEnum>::value>::type>
66struct T_EnumIsIterable : public std::false_type
67{
68 #if DOXYGEN
69 /// Specializations have to implement this static method to return the first enum element
70 /// of the iteration.
71 ///
72 /// @return The first enumeration element.
73 static constexpr TEnum Begin;
74 #endif
75
76 #if DOXYGEN
77 /// Specializations have to implement this static method to return the element value after
78 /// the last enum element of the iteration.
79 ///
80 /// @return The element after the last enumeration element.
81 static constexpr TEnum End;
82 #endif
83
84};
85
86}} // namespace [alib::enums]
87
88// #################################################################################################
89// Helper Macros
90// #################################################################################################
91
92#define ALIB_ENUMS_MAKE_ITERABLE_BEGIN_END(TEnum, StartElement, StopElement ) \
93namespace alib::enums { \
94template<> struct T_EnumIsIterable<TEnum> : std::true_type \
95{ \
96 static constexpr TEnum Begin = StartElement; \
97 static constexpr TEnum End = StopElement; \
98};}
99
100#define ALIB_ENUMS_MAKE_ITERABLE(TEnum, StopElement ) \
101ALIB_ENUMS_MAKE_ITERABLE_BEGIN_END( TEnum, TEnum(0), StopElement )
102
103
104// #################################################################################################
105// Operators for iterable enums
106// #################################################################################################
107
108// For documentation, all operators and enum related template functions are faked into namespace
109// alib::enums
110#if DOXYGEN
111namespace alib { namespace enums {
112/// Operators available to elements of enumerations if \alib{enums;T_EnumIsIterable} is
113/// specialized.
114///
115/// \note
116/// This namespace exits only in the documentation to collect the operators.
117/// When parsed by a C++ compiler, <b>the operators reside in the global namespace</b>.
118namespace iterable {
119#endif
120
121#if DOXYGEN
122/// Add operator usable with scoped enum types and integral values.
123///
124/// Selected by the compiler only if \alib{enums;T_EnumIsIterable} is specialized for
125/// enum type \p{TEnum}.
126///
127/// @tparam TEnum Enumeration type.
128/// @tparam TRhs The type of the summand.
129/// @param element First operand of \p{TEnum} type.
130/// @param summand The summand.
131/// @return The <em>"summand-th"</em> enum element after \p{element} .
132template<typename TEnum, typename TRhs=int>
133constexpr
134TEnum operator+ (TEnum element, TRhs summand) noexcept;
135#else
136template<typename TEnum, typename TRhs= int>
137constexpr
139 && ATMP_IS_INT(const TRhs) )
140operator+ (TEnum element, TRhs summand) noexcept
141{
142 return TEnum( alib::UnderlyingIntegral(element)
143 + static_cast<typename std::underlying_type<TEnum>::type>(summand) );
144}
145#endif
146
147#if DOXYGEN
148/// Subtract operator usable with scoped enum types and integral values.
149///
150/// Selected by the compiler only if \alib{enums;T_EnumIsIterable} is specialized for
151/// enum type \p{TEnum}.
152///
153/// @tparam TEnum Enumeration type.
154/// @tparam TRhs The type of the subtrahend.
155/// @param element First operand of \p{TEnum} type.
156/// @param subtrahend The subtrahend.
157/// @return The <em>"subtrahend-th"</em> enum element before \p{element} .
158template<typename TEnum, typename TRhs=int>
159constexpr
160TEnum operator- (TEnum element, TRhs subtrahend) noexcept;
161#else
162
163template<typename TEnum, typename TRhs= int>
164constexpr
166 && ATMP_IS_INT(const TRhs) )
167operator- (TEnum element, typename std::underlying_type<TEnum>::type subtrahend) noexcept
168{
169 return TEnum( alib::UnderlyingIntegral(element)
170 - static_cast<typename std::underlying_type<TEnum>::type>(subtrahend) );
171}
172#endif
173
174
175// Faking all operators and enum related template functions to namespace alib::enums
176#if DOXYGEN
177}
178#else
179 namespace alib { namespace enums {
180#endif
181
182
183// #################################################################################################
184// EnumIterator
185// #################################################################################################
186#if DOXYGEN
187//==================================================================================================
188/// Implements a \c std::iterator_traits class for scoped and non-scoped enum types.
189/// The documentation is found with TMP struct \alib{enums;T_EnumIsIterable}, which needs to be
190/// specialized for template type \p{TEnum}. For other types, this class is not constructible.
191///
192/// @tparam TEnum The enum type to iterate over.
193/// @tparam TEnableIf This parameter has a default expressions and <b>must not</b> be provided
194/// with specializations of this struct.
195/// It is used internally to ensure that only if a specialization of
196/// \alib{enums;T_EnumIsIterable;T_EnumIsIterable<TEnum>} exists, this class
197/// is available.
198//==================================================================================================
199template<typename TEnum, typename TEnableIf>
201#else
202template<typename TEnum, typename TEnableIf
204struct EnumIterator
205#endif
206{
207 //==============================================================================================
208 /// Default constructor.
209 //==============================================================================================
210 EnumIterator()= default;
211
212 //==============================================================================================
213 /// Implementation of \c std::iterator_traits for enum type \p{TEnum}. This class exposes
214 /// #ConstIterator which uses <c>const TEnum*</c> and <c>const TEnum&</c> as
215 /// pointer and reference types.
216 ///
217 /// As the name of the class indicates, this iterator satisfies the C++ standard library concept
218 /// \https{RandomAccessIterator,en.cppreference.com/w/cpp/concept/RandomAccessIterator}.
219 //==============================================================================================
220 template<typename TPointer, typename TReference>
222 {
223 using iterator_category = std::random_access_iterator_tag; ///< Implementation of <c>std::iterator_traits</c>.
224 using value_type = TEnum ; ///< Implementation of <c>std::iterator_traits</c>.
225 using difference_type = std::ptrdiff_t ; ///< Implementation of <c>std::iterator_traits</c>.
226 using pointer = TPointer ; ///< Implementation of <c>std::iterator_traits</c>.
227 using reference = TReference ; ///< Implementation of <c>std::iterator_traits</c>.
228
229 protected:
230 /// The actual enum element.
231 TEnum p;
232
233 /// The underlying integer type.
234 using TIntegral= typename std::underlying_type<TEnum>::type;
235
236
237 public:
238 /// Constructor.
239 /// @param _p Our initial value
240 constexpr
241 explicit TRandomAccessIterator( TEnum _p = TEnum(0) ) : p(_p)
242 {
243 }
244
245 //###################### To satisfy concept of InputIterator ######################
246
247 /// Prefix increment operator.
248 /// @return A reference to ourselves.
250 {
252 p= p + 1;
253 else
254 p= TEnum( UnderlyingIntegral( p ) << 1 );
255
256 return *this;
257 }
258
259 /// Postfix increment operator.
260 /// @return A reference to ourselves.
261 TRandomAccessIterator operator++(typename std::underlying_type<TEnum>::type)
262 {
264 return TRandomAccessIterator(p= p + 1);
265 else
266 return TRandomAccessIterator(p= TEnum( UnderlyingIntegral( p ) << 1) );
267 }
268
269 /// Comparison operator.
270 /// @param other The iterator to compare ourselves to.
271 /// @return \c true if this and given iterator are equal, \c false otherwise.
272 constexpr
274 {
275 return p == other.p;
276 }
277
278 /// Comparison operator.
279 /// @param other The iterator to compare ourselves to.
280 /// @return \c true if this and given iterator are not equal, \c false otherwise.
281 constexpr
283 {
284 return !(*this == other);
285 }
286
287 /// Retrieves the enum element that this iterator references.
288 /// @return The enum element.
289 constexpr
290 TEnum operator*() const
291 {
292 return p;
293 }
294
295
296 //################## To satisfy concept of BidirectionalIterator ##################
297
298 /// Prefix decrement operator.
299 /// @return A reference to ourselves.
301 {
303 p= p + 1;
304 else
305 p= TEnum( );
306 return *this;
307 }
308
309
310 /// Postfix decrement operator.
311 /// @return An iterator that with the old value.
312 TRandomAccessIterator operator--(typename std::underlying_type<TEnum>::type)
313 {
315 return TRandomAccessIterator(p= p - 1);
316 else
317 return TRandomAccessIterator(p= TEnum( UnderlyingIntegral( p ) >> 1) );
318 }
319
320
321 //################## To satisfy concept of RandomAccessIterator ###################
322
323 /// Addition assignment.
324 /// @param n The value to subtract.
325 /// @return A reference to ourselves.
327 {
329 p= p + n;
330 else
331 p= TEnum( UnderlyingIntegral( p ) << n );
332 return *this;
333 }
334
335 /// Subtraction assignment.
336 /// @param n The value to subtract.
337 /// @return A reference to ourselves.
339 {
341 p= p - n;
342 else
343 p= TEnum( UnderlyingIntegral( p ) >> n );
344 }
345
346 /// Addition.
347 /// @param n The value to subtract.
348 /// @return A reference to the new iterator.
350 {
352 return TRandomAccessIterator( p + n );
353 else
354 return TRandomAccessIterator( TEnum( UnderlyingIntegral( p ) << n ) );
355 }
356
357 /// Subtraction.
358 /// @param n The value to subtract.
359 /// @return A reference to the new iterator.
361 {
363 return TRandomAccessIterator( p - n );
364 else
365 return TRandomAccessIterator( TEnum( UnderlyingIntegral( p ) >> n ) );
366 }
367
368 /// Difference (distance) from this iterator to the given one.
369 /// @param other The iterator to subtract
370 /// @return The iterator to subtract.
371 std::ptrdiff_t operator-(TRandomAccessIterator other) const
372 {
374 return static_cast<std::ptrdiff_t>(UnderlyingIntegral(p) - UnderlyingIntegral(other.p));
375 else
376 return static_cast<std::ptrdiff_t>(lang::MSB(UnderlyingIntegral( p ) ))
377 - static_cast<std::ptrdiff_t>(lang::MSB(UnderlyingIntegral( other.p ) ));
378 }
379
380 /// Subscript operator.
381 /// @param n The iterator to subtract
382 /// @return <c>*( (*this) + n )</c>.
383 TEnum operator[]( std::ptrdiff_t n ) const
384 {
386 return ( p + static_cast<TIntegral>( n ) );
387 else
388 return TEnum( UnderlyingIntegral( p ) << n );
389 }
390
391 //#### Comparison operators (also needed to satisfy concept of RandomAccessIterator) ###
392
393 /// Compares this iterator with the given one.
394 /// @param other The iterator to compare
395 /// @return \c true if this iterator is \e smaller than \p{other},
396 /// \c false otherwise.
398 {
399 return p < other.p;
400 }
401
402 /// Compares this iterator with the given one.
403 /// @param other The iterator to compare
404 /// @return \c true if this iterator is \e smaller than or equal to \p{other},
405 /// \c false otherwise.
407 {
408 return p <= other.p;
409 }
410
411
412 /// Compares this iterator with the given one.
413 /// @param other The iterator to compare
414 /// @return \c true if this iterator is \e greater than \p{other},
415 /// \c false otherwise.
417 {
418 return p > other.p;
419 }
420
421 /// Compares this iterator with the given one.
422 /// @param other The iterator to compare
423 /// @return \c true if this iterator is \e greater than or equal to \p{other},
424 /// \c false otherwise.
426 {
427 return p >= other.p;
428 }
429 };
430
431 /// The constant iterator exposed by this class. A Mutable version is not available.
433
434
435 /// Returns an iterator referring to the start of enumeration \p{TEnum}.
436 /// @return The start of the enumeration.
444
445 /// Returns an iterator referring the first illegal value of enumeration \p{TEnum}.
446 /// @return The end of the enumeration.
448 {
450 }
451}; // struct EnumIterator
452
453
454
455
456} // namespace alib[::enums]
457
458#if DOXYGEN
459
460/// Type alias in namespace \b alib.
461template<typename TEnum, typename TEnableIf= void>
463
464#else
465
466template<typename TEnum, typename TEnableIf
469
470#endif
471
472} // namespace [alib]
473
474#endif // HPP_ALIB_ENUMS_ITERABLE
475
bool operator<=(TRandomAccessIterator other) const
Definition iterable.hpp:406
TEnum operator[](std::ptrdiff_t n) const
Definition iterable.hpp:383
std::ptrdiff_t operator-(TRandomAccessIterator other) const
Definition iterable.hpp:371
constexpr TRandomAccessIterator(TEnum _p=TEnum(0))
Definition iterable.hpp:241
TRandomAccessIterator operator-(TIntegral n) const
Definition iterable.hpp:360
bool operator<(TRandomAccessIterator other) const
Definition iterable.hpp:397
typename std::underlying_type< TEnum >::type TIntegral
The underlying integer type.
Definition iterable.hpp:234
bool operator>=(TRandomAccessIterator other) const
Definition iterable.hpp:425
TRandomAccessIterator operator--(typename std::underlying_type< TEnum >::type)
Definition iterable.hpp:312
TEnum value_type
Implementation of std::iterator_traits.
Definition iterable.hpp:224
TRandomAccessIterator operator+(TIntegral n) const
Definition iterable.hpp:349
TRandomAccessIterator & operator-=(TIntegral n)
Definition iterable.hpp:338
std::random_access_iterator_tag iterator_category
Implementation of std::iterator_traits.
Definition iterable.hpp:223
constexpr bool operator==(TRandomAccessIterator other) const
Definition iterable.hpp:273
TRandomAccessIterator & operator+=(TIntegral n)
Definition iterable.hpp:326
bool operator>(TRandomAccessIterator other) const
Definition iterable.hpp:416
TPointer pointer
Implementation of std::iterator_traits.
Definition iterable.hpp:226
constexpr bool operator!=(TRandomAccessIterator other) const
Definition iterable.hpp:282
std::ptrdiff_t difference_type
Implementation of std::iterator_traits.
Definition iterable.hpp:225
TReference reference
Implementation of std::iterator_traits.
Definition iterable.hpp:227
TRandomAccessIterator operator++(typename std::underlying_type< TEnum >::type)
Definition iterable.hpp:261
#define ATMP_IS_INT(T)
Definition tmp.hpp:24
#define ALIB_ASSERT_MODULE(modulename)
Definition alib.hpp:223
#define ATMP_VOID_IF(Cond)
Definition tmp.hpp:47
#define ATMP_EQ( T, TEqual)
Definition tmp.hpp:27
#define ATMP_T_IF(T, Cond)
Definition tmp.hpp:49
constexpr TEnum operator-(TEnum element, TRhs subtrahend) noexcept
constexpr TEnum operator+(TEnum element, TRhs summand) noexcept
constexpr std::underlying_type< TEnum >::type UnderlyingIntegral(TEnum element) noexcept
constexpr int MSB(TIntegral value)
Definition alib.cpp:69
ConstIterator end() const
Definition iterable.hpp:447
TRandomAccessIterator< const TEnum *, const TEnum & > ConstIterator
The constant iterator exposed by this class. A Mutable version is not available.
Definition iterable.hpp:432
ConstIterator begin() const
Definition iterable.hpp:437
EnumIterator()=default
Default constructor.
static constexpr TEnum Begin
Definition iterable.hpp:73
static constexpr TEnum End
Definition iterable.hpp:81