ALib C++ Library
Library Version: 2412 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
enum.hpp
Go to the documentation of this file.
1//==================================================================================================
2/// \file
3/// This header file is part of module \alib_boxing 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_BOXING_ENUM
9#define HPP_ALIB_BOXING_ENUM 1
10#pragma once
12
13#if ALIB_ENUMS
14# include "alib/enums/records.hpp"
15#endif
16
17#include <typeindex>
18
19namespace alib { namespace boxing {
20
21//==================================================================================================
22/// This class is useful to pass and accept enum values of arbitrary C++ scoped enum types.
23/// Based on class \alib{boxing;Box}, all interfaces are inherited, including type guessing and
24/// unboxing.
25///
26/// In the constructor, enum elements of an arbitrary type are accepted.
27/// The element's underlying integral value is boxed, and thus run-time type-information is added.
28/// Having the "original" element stored in protected base class \b Box, has the following
29/// advantages:
30///
31/// \note
32/// The implementation of this class, by deriving from class \b Box, introduces a
33/// small memory overhead (usually 8 bytes per instance on 64-bit system), in respect to a
34/// possible alternative "direct" implementation. This is due to the fact that boxing allows
35/// one dimensional array types to be boxed as well as scalar types - which is never the case
36/// with this class.<br>
37/// But the advantages of doing so certainly surpass this small drawback.
38///
39/// \note
40/// Class \b Box is inherited \c protected instead of public, to hide bigger portions of
41/// the base class's interface. While some functions are explicitly made visible with
42/// keyword \c using, for others, instances of this class have to be cased using
43/// overloaded methods #CastToBox.
44///
45/// ## Functors In Namespace std ##
46/// Functors <c>std::hash</c>, <c>std::equal_to</c> and <c>std::less</c> are specialized for
47/// this type with the inclusion of header file \alibheader{compatibility/std_boxing_functional.hpp}
48/// as documented with namespace #alib::compatibility::std.
49///
50/// ## Friends ##
51/// class \alib{boxing;Box}
52//==================================================================================================
53struct Enum : protected Box
54{
55 #if !DOXYGEN
56 friend class Box;
57 #endif
58
59 //==============================================================================================
60 /// Default constructor.
61 //==============================================================================================
63 : Box(nullptr)
64 {}
65
66 #if DOXYGEN
67 //==============================================================================================
68 /// Implicit constructor, which accepts arbitrary elements of scoped or non-scoped enum types.
69 ///
70 /// @tparam TEnum The external (user specific) enumeration type.
71 /// @tparam TEnableIf Selects this constructor only for enum types. Must not be specified
72 /// (deduced by the compiler).
73 /// @param element The external (user specific) enumeration element.
74 //==============================================================================================
75 template<typename TEnum, typename TEnableIf>
76 inline
77 constexpr Enum( TEnum element );
78 #else
79 template<typename TEnum,
80 typename TEnableIf = typename std::enable_if<std::is_enum<TEnum>::value>::type >
81 constexpr Enum( TEnum element )
82 : Box( element ) {}
83 #endif
84
85 #if DOXYGEN
86 //==============================================================================================
87 /// This is a shortcut to \alib{boxing;Box::Unbox;Box::Unbox<TEnum>()} to retrieve the
88 /// original enum element in a type-safe way.
89 ///
90 /// Before invoking this, the boxed type can be checked with #IsType. If the wrong type
91 /// is tried to be received, an \alib assertion is raised.
92 ///
93 /// @tparam TEnum The external (user specific) enumeration type.
94 /// @return The underlying integral value of the encapsulated enum element.
95 //==============================================================================================
96 template<typename TEnum>
97 inline
98 TEnum Get() const;
99 #else
100 template<typename TEnum>
101 ATMP_T_IF(TEnum, std::is_enum<TEnum>::value )
102 Get() const
103 {
104 return Unbox<TEnum>();
105 }
106 #endif
107
108 //==============================================================================================
109 /// Returns the underlying integral value of the original enum element cast to type
110 /// \alib{integer}.
111 ///
112 /// \note
113 /// Boxed enum element values are always
114 /// \ref alib_boxing_enums_integer "stored as type integer", regardless of the
115 /// underlying type of the enumeration.
116 ///
117 /// @return The underlying integral value.
118 //==============================================================================================
120 {
121 return data.Integrals.Int;
122 }
123
124 //==============================================================================================
125 /// Comparison operator.
126 ///
127 /// @param rhs The right hand side argument of the comparison.
128 /// @return \c true if this object equals \p{rhs}, \c false otherwise.
129 //==============================================================================================
130 bool operator==(const Enum& rhs) const
131 {
132 return this->CastToBox() == rhs.CastToBox();
133 }
134
135 //==============================================================================================
136 /// Comparison operator.
137 ///
138 /// @param rhs The right hand side argument of the comparison.
139 /// @return \c true if this object does not equal \p{rhs}, \c false otherwise.
140 //==============================================================================================
141 bool operator!=(const Enum& rhs) const
142 {
143 return this->CastToBox() != rhs.CastToBox();
144 }
145
146 #if DOXYGEN
147 //==============================================================================================
148 /// Imports \c protected base class's method \alib{boxing;Box::TypeID}.
149 /// @return The \c std::type_info of the mapped \c enum type.
150 //==============================================================================================
151 using Box::TypeID;
152
153 //==============================================================================================
154 /// Imports \c protected base class's method \alib{boxing;Box::Hashcode}.
155 /// @return A hashcode for the boxed enum type and value.
156 //==============================================================================================
157 using Box::Hashcode;
158 #else
159 using Box::TypeID;
160 using Box::Hashcode;
161 #endif
162
163 //==============================================================================================
164 /// This method casts an instance of this class to a reference of base class \b Box.
165 /// To hide the bases class's interface, this class inherits class \b Box only as
166 /// a \c protected base. With this method, this "artificial limitation " (its a design decision)
167 /// is lifted.
168 ///
169 /// @return A mutable reference to this object.
170 //==============================================================================================
172 {
173 return static_cast<Box&>(*this);
174 }
175
176 //==============================================================================================
177 /// Same as overloaded version, but returns a \c const reference and consequently this method
178 /// is declared\c const itself.
179 ///
180 /// @return A constant reference to this object.
181 //==============================================================================================
182 const Box& CastToBox() const
183 {
184 return static_cast<const Box&>(*this);
185 }
186
187
188 #if DOXYGEN
189 //==============================================================================================
190 /// Checks if this instance has an enum element of type \p{TEnum} stored.<br>
191 /// This method is an inlined, simple alias for \c protected base class's method
192 /// \alib{boxing;Box::IsType}.
193 ///
194 ///
195 /// @tparam TEnum The external (user specific) enumeration type.
196 /// @return \c true if the encapsulated enum type of type \p{TEnum}, otherwise \c false.
197 //==============================================================================================
198 template<typename TEnum>
199 inline
200 bool IsEnumType() const;
201 #else
202 template<typename TEnum>
203 ATMP_T_IF(bool, std::is_enum<TEnum>::value)
204 IsEnumType() const
205 {
206 return Box::IsType<TEnum>();
207 }
208 #endif
209
210 #if DOXYGEN
211 //==============================================================================================
212 /// Comparison operator with enum elements.
213 ///
214 /// @tparam TEnum The external (user specific) enumeration type.
215 /// @param rhs The right hand side argument of the comparison.
216 /// @return \c true if this object equals \p{rhs}, \c false otherwise.
217 //==============================================================================================
218 template<typename TEnum>
219 inline
220 bool operator==(TEnum rhs) const;
221 #else
222 template<typename TEnum>
223 ATMP_T_IF(bool, std::is_enum<TEnum>::value)
224 operator==(TEnum rhs) const
225 {
226 return Integral() == static_cast<typename std::underlying_type<TEnum>::type>( rhs )
227 && TypeID() == typeid( TEnum );
228 }
229 #endif
230
231 #if DOXYGEN
232 //==============================================================================================
233 /// Comparison operator with enum elements.
234 ///
235 /// @tparam TEnum The external (user specific) enumeration type.
236 /// @param rhs The right hand side argument of the comparison.
237 /// @return \c true if this object does not equal \p{rhs}, \c false otherwise.
238 //==============================================================================================
239 template<typename TEnum>
240 inline
241 bool operator!=(TEnum rhs) const;
242 #else
243 template<typename TEnum>
244 ATMP_T_IF(bool, std::is_enum<TEnum>::value)
245 operator!=(TEnum rhs) const
246 {
247 return Integral() != static_cast<typename std::underlying_type<TEnum>::type>( rhs )
248 || TypeID() != typeid( TEnum );
249 }
250 #endif
251
252
253 //==============================================================================================
254 /// Comparison operator with another \b Enum object.
255 /// The sort order is primarily determined by the enum types that were boxed.
256 /// If those are the same, then the underlying integral value of the enum elements is compared.
257 ///
258 /// This leads to a nested sort order, with the type information being the outer order and
259 /// the integral value of the enum being the inner one.
260 ///
261 /// \note
262 /// It is a matter of the compiler how the outer sort of types is performed and thus this
263 /// cannot be determined by the user code.
264 ///
265 ///
266 /// @param rhs The right hand side argument of the comparison.
267 /// @return If the encapsulated type of this instance is the same as that of \p{rhs}, this
268 /// methods returns \c true if #Integral() of this object is smaller than the one of
269 /// \p{rhs} and otherwise \c false. If the types are not the same, than the result is
270 /// dependent on the tool chain (compiler) used for compiling \alib.
271 //==============================================================================================
272 bool operator< (Enum const& rhs) const
273 {
274 return ( std::type_index( TypeID() )
275 < std::type_index(rhs.TypeID() ) )
276 || ( TypeID() == rhs.TypeID()
277 && Integral() < rhs.Integral() );
278 }
279
280 #if ALIB_ENUMS
281
282 //==========================================================================================
283 /// Returns the \ref alib_enums_records "ALib Enum Record" associated with this enumeration
284 /// element.<br>
285 /// In debug-compilations an \alib assertion is raised, if no enum record was defined for
286 /// the enumeration element represented by this instance.
287 ///
288 /// \see
289 /// - Namespace function \alib{enums::GetRecord} of module \alib_enums, which provides the
290 /// standard way of accessing enum records for enum elements known at compile-time.
291 /// - Sibling method #TryRecord.
292 ///
293 /// @tparam TRecord The enumeration record type associated with the enum type.
294 /// This has to be explicitly provided.
295 /// It is the caller's obligation to ensure that the requested type equals
296 /// the one associated. Otherwise this method produces undefined behavior.
297 ///
298 /// @return The record that is associated with this enumeration element.
299 //==========================================================================================
300 template<typename TRecord>
301 const TRecord& GetRecord()
302 {
303 const void* result= enums::detail::getEnumRecord( TypeID(), Integral() );
304 #if ALIB_STRINGS
305 ALIB_ASSERT_ERROR( result != nullptr, "BOXING",
306 NString128() << "Enum Record for type <" << lang::DbgTypeDemangler(TypeID()).Get()
307 << ">(" << Integral() << ") not found." )
308 #else
309 ALIB_ASSERT_ERROR( result != nullptr,
310 "BOXING: Enum Record for type not found: ",
311 DbgTypeDemangler(TypeID()).Get() )
312 #endif
313
314
315 return *reinterpret_cast<const TRecord*>( result );
316 }
317
318 //==========================================================================================
319 /// Returns a pointer to the \ref alib_enums_records "ALib Enum Record" associated with this
320 /// the enumeration element represented by this instance.
321 /// If no enum record was is defined, \c nullptr is returned.
322 ///
323 /// \see
324 /// - Namespace function \alib{enums::TryRecord} of module \alib_enums, which provides the
325 /// standard way of accessing enum records for enum elements known at compile-time.
326 /// - Sibling method #GetRecord.
327 ///
328 /// @tparam TRecord The enumeration record type associated with the enum type.
329 /// This has to be explicitly provided.
330 /// It is the caller's obligation to ensure that the requested type equals
331 /// the one associated. Otherwise this method produces undefined behavior.
332 ///
333 /// @return A pointer to the record that is associated with this enumeration element,
334 /// respectively \c nullptr if no record was found.
335 //==========================================================================================
336 template<typename TRecord>
337 const TRecord* TryRecord()
338 {
339 return reinterpret_cast<const TRecord*>( enums::detail::getEnumRecord( TypeID(), Integral() ) );
340 }
341
342 #endif // ALIB_ENUMS
343
344}; // class Enum
345
346} // namespace alib[::boxing]
347
348/// Type alias in namespace \b alib.
350
351} // namespace [alib]
352
353// #################################################################################################
354// T_Append<Enum>
355// #################################################################################################
356#if ALIB_STRINGS
357
358 #if !defined (HPP_ALIB_STRINGS_ASTRING)
359 # include "alib/strings/astring.hpp"
360 #endif
361
362
363 namespace alib { namespace strings {
364 // Faking all template specializations of namespace strings for doxygen into namespace
365 // strings::APPENDABLES to keep the documentation of namespace string clean!
366 #if DOXYGEN
367 namespace APPENDABLES {
368 #endif
369
370 /// Specialization of functor \alib{strings;T_Append} for type \alib{boxing;Enum}.
371 /// @tparam TChar The character type of the target \b %Astring.
372 /// @tparam TAllocator The allocator that the target \b %AString uses, as prototyped
373 /// with \alib{lang;Allocator}.
374 template<typename TChar, typename TAllocator> struct T_Append<boxing::Enum, TChar,TAllocator>
375 {
376 //======================================================================================
377 /// Writes the given boxed object. This is done by invoking box-function
378 /// \alib{boxing;FAppend} on box \p{value}.
379 ///
380 /// @param target The \b AString that \b Append was invoked on.
381 /// @param value The enum-box to its contents to \p{target}.
382 //======================================================================================
384 {
386 }
387
388 };
389
390 #if DOXYGEN
391 } // namespace alib::strings[::appendables]
392 #endif
393 }} // namespace [alib::strings]
394
395#endif // ALIB_STRINGS
396
397
398#endif // HPP_ALIB_BOXING_ENUM
399
ALIB_API size_t Hashcode() const
Definition boxing.cpp:163
bool IsType() const
Placeholder data
The data that we encapsulate.
Definition box.inl:50
decltype(std::declval< typename TFDecl::Signature >()(std::declval< Box & >(), std::declval< TArgs >()...)) Call(TArgs &&... args) const
Definition box.inl:1175
const std::type_info & TypeID() const
Definition box.inl:941
const TUnboxable Unbox() const
#define ALIB_ASSERT_ERROR(cond,...)
Definition alib.hpp:1271
#define ATMP_T_IF(T, Cond)
Definition tmp.hpp:49
ALIB_API const void * getEnumRecord(const std::type_info &rtti, integer integral)
Definition records.cpp:59
Definition alib.cpp:69
NLocalString< 128 > NString128
Type alias name for TLocalString<nchar,128>.
lang::integer integer
Type alias in namespace alib.
Definition integers.hpp:273
constexpr Enum(TEnum element)
Enum()
Default constructor.
Definition enum.hpp:62
integer Integral() const
Definition enum.hpp:119
bool operator<(Enum const &rhs) const
Definition enum.hpp:272
const TRecord & GetRecord()
Definition enum.hpp:301
const TRecord * TryRecord()
Definition enum.hpp:337
TEnum Get() const
const Box & CastToBox() const
Definition enum.hpp:182
bool operator==(const Enum &rhs) const
Definition enum.hpp:130
Box & CastToBox()
Definition enum.hpp:171
bool operator==(TEnum rhs) const
bool operator!=(TEnum rhs) const
bool operator!=(const Enum &rhs) const
Definition enum.hpp:141
const std::type_info & TypeID() const
Definition box.inl:941
bool IsEnumType() const
void operator()(TAString< TChar, TAllocator > &target, const boxing::Enum &value)
Definition enum.hpp:383
detail::UnionIntegrals Integrals
Collection of integrals of different sizes.
integer Int
Signed integral of platform-dependent size.