12#ifndef JAU_ENUM_UTIL_HPP_
13#define JAU_ENUM_UTIL_HPP_
76 template<
typename E, E V>
79 return JAU_PRETTY_FUNCTION;
83 std::enable_if_t<std::is_enum_v<
decltype(V)>>* =
nullptr>
88 size_t i =
name.rfind(
' ');
89 if ( std::string_view::npos == i || i+1 ==
name.length() ) {
93 const char c =
name[i];
94 return !(c >=
'0' && c <=
'9');
98 std::enable_if_t<std::is_enum_v<
decltype(V)>>* =
nullptr>
101 constexpr std::string_view sym(
enum_funcname<
decltype(V), V>());
102 size_t i = sym.rfind(
' ');
103 if ( std::string_view::npos == i || i+1 == sym.length() ) {
107 const char c = sym[i];
108 if ( c >=
'0' && c <=
'9' ) {
111 if constexpr ( sym[sym.length() - 1] ==
']' ) {
112 return sym.substr(i, sym.length()-i-1);
114 return sym.substr(i);
118 std::enable_if_t<std::is_enum_v<
decltype(V)>>* =
nullptr>
121 constexpr std::string_view sym(
enum_funcname<
decltype(V), V>());
123 size_t i = sym.rfind(
' ');
124 if ( std::string_view::npos == i || i+1 == sym.length() ) {
128 const char c = sym[i];
129 if ( c >=
'0' && c <=
'9' ) {
133 size_t j = sym.find(
"::", i);
134 if ( std::string_view::npos == j || j+2 >= sym.length() ) {
138 if constexpr ( sym[sym.length() - 1] ==
']' ) {
139 return sym.substr(j, sym.length()-j-1);
141 return sym.substr(j);
144 template <
auto... Vargs>
146 std::string_view
names[
sizeof...(Vargs)];
148 template <
auto... Vargs>
154 template <
typename E,
size_t N>
158 template <
typename... Args>
159 constexpr ValueTable<std::common_type_t<Args...>,
sizeof...(Args)>
161 return { { args... } };
164 template <
typename E, std::enable_if_t<std::is_enum_v<E>>* =
nullptr>
165 constexpr std::underlying_type_t<E>
166 number(
const E v)
noexcept {
return static_cast<std::underlying_type_t<E>
>(v); }
168 template <
typename E, std::enable_if_t<std::is_enum_v<E>>* =
nullptr>
169 constexpr std::underlying_type_t<E>
170 operator*(
const E v)
noexcept {
return static_cast<std::underlying_type_t<E>
>(v); }
172 template<
typename E, std::enable_if_t<std::is_enum_v<E>>* =
nullptr>
177 template<
typename E, std::enable_if_t<std::is_enum_v<E>>* =
nullptr>
178 constexpr E
operator^(
const E lhs,
const E rhs)
noexcept {
179 return E(*lhs ^ *rhs);
182 template<
typename E, std::enable_if_t<std::is_enum_v<E>>* =
nullptr>
183 constexpr E
operator|(
const E lhs,
const E rhs)
noexcept {
184 return E(*lhs | *rhs);
187 template<
typename E, std::enable_if_t<std::is_enum_v<E>>* =
nullptr>
188 constexpr E
operator&(
const E lhs,
const E rhs)
noexcept {
189 return E(*lhs & *rhs);
192 template<
typename E, std::enable_if_t<std::is_enum_v<E>>* =
nullptr>
194 return lhs = lhs | rhs;
197 template<
typename E, std::enable_if_t<std::is_enum_v<E>>* =
nullptr>
199 return lhs = lhs & rhs;
209 template<
typename E, std::enable_if_t<std::is_enum_v<E>>* =
nullptr>
210 constexpr E&
write(E& store,
const E bits,
bool set)
noexcept {
212 return store = store | bits;
214 return store = store & ~bits;
218 template<
typename E, std::enable_if_t<std::is_enum_v<E>>* =
nullptr>
220 return lhs = lhs ^ rhs;
223 template<
typename E, std::enable_if_t<std::is_enum_v<E>>* =
nullptr>
224 constexpr bool operator==(
const E lhs,
const E rhs)
noexcept {
228 template<
typename E, std::enable_if_t<std::is_enum_v<E>>* =
nullptr>
229 constexpr bool operator!=(
const E lhs,
const E rhs)
noexcept {
230 return !(lhs == rhs);
233 template<
typename E, std::enable_if_t<std::is_enum_v<E>>* =
nullptr>
234 constexpr bool is_set(
const E mask,
const E bits)
noexcept {
235 return bits == (mask & bits);
238 template<
typename E, std::enable_if_t<std::is_enum_v<E>>* =
nullptr>
239 constexpr bool has_any(
const E mask,
const E bits)
noexcept {
240 return std::underlying_type_t<E>(0) != ( *mask & *bits );
243 template<
typename E, std::enable_if_t<std::is_enum_v<E>>* =
nullptr>
244 constexpr void append_bitstr(std::string& out, E mask, E bit,
const std::string& bitstr,
bool& comma) {
245 if( bit == (mask & bit) ) {
246 if( comma ) { out.append(
", "); }
247 out.append(bitstr); comma =
true;
251 template <
typename T,
252 std::enable_if_t<std::is_enum_v<T>>* =
nullptr>
258 template <
typename EnumType,
auto... Vargs>
class enum_iterator;
263 template <
typename EnumType,
auto... Vargs>
294 constexpr iterator_base_t begin_iter() const noexcept {
return &values_[0]; }
295 constexpr iterator_base_t end_iter() const noexcept {
return &values_[0] +
size(); }
299 : values_({{ Vargs... }})
303 constexpr enum_info(
const enum_info& o)
noexcept =
delete;
306 static enum_info singleton;
324 template<
class,
class =
void >
334 template <typename enum_info_t, std::enable_if_t<is_enum_info<enum_info_t>::value>* =
nullptr>
335 inline std::ostream&
operator<<(std::ostream&
os,
const enum_info_t& v) {
336 os << v.name() <<
"[";
337 typename enum_info_t::iterator end = v.end();
339 for(
typename enum_info_t::iterator iter = v.begin(); iter != end; ++iter, comma=
true) {
340 typename enum_info_t::value_type ev = *iter;
344 os << ev <<
" (" << std::to_string( *ev ) <<
")";
353 template <
typename EnumType,
auto... Vargs>
354 class enum_iterator {
376 friend class enum_info<EnumType, Vargs...>;
379 : info_(info), iterator_(iter)
397 constexpr enum_iterator&
operator=(
const enum_iterator& o)
noexcept =
default;
414 constexpr enum_iterator&
operator=(enum_iterator&& o)
noexcept =
default;
421 void swap(enum_iterator& o)
noexcept {
422 std::swap( info_, o.info_);
423 std::swap( iterator_, o.iterator_);
434 constexpr bool is_end() const noexcept {
return iterator_ == info_.end_iter(); }
439 constexpr enum_iterator&
to_end() noexcept
440 { iterator_ = info_.end_iter();
return *
this; }
450 constexpr bool is_begin() const noexcept {
return iterator_ == info_.begin_iter(); }
456 { iterator_ = info_.begin_iter();
return *
this; }
475 constexpr int compare(
const enum_iterator& rhs)
const noexcept {
476 return iterator_ == rhs.iterator_ ? 0
477 : ( iterator_ < rhs.iterator_ ? -1 : 1);
481 constexpr bool operator==(
const enum_iterator& rhs)
const noexcept
482 {
return iterator_ == rhs.iterator_; }
485 std::strong_ordering
operator<=>(
const enum_iterator& rhs)
const noexcept {
486 return iterator_ == rhs.iterator_ ? std::strong_ordering::equal :
487 ( iterator_ < rhs.iterator_ ? std::strong_ordering::less : std::strong_ordering::greater );
505 return &(*iterator_);
516 {
return enum_iterator(info_, iterator_++); }
528 {
return enum_iterator(info_, iterator_--); }
534 {
return iterator_[i]; }
538 { iterator_ += i;
return *
this; }
542 {
return enum_iterator(info_, iterator_ + rhs); }
546 { iterator_ -= i;
return *
this; }
550 {
return enum_iterator(info_, iterator_ - rhs); }
556 {
return iterator_ - rhs.iterator_; }
578#define JAU_EXPAND(...) JAU_EXPAND4(JAU_EXPAND4(JAU_EXPAND4(JAU_EXPAND4(__VA_ARGS__))))
579#define JAU_EXPAND4(...) JAU_EXPAND3(JAU_EXPAND3(JAU_EXPAND3(JAU_EXPAND3(__VA_ARGS__))))
580#define JAU_EXPAND3(...) JAU_EXPAND2(JAU_EXPAND2(JAU_EXPAND2(JAU_EXPAND2(__VA_ARGS__))))
581#define JAU_EXPAND2(...) JAU_EXPAND1(JAU_EXPAND1(JAU_EXPAND1(JAU_EXPAND1(__VA_ARGS__))))
582#define JAU_EXPAND1(...) __VA_ARGS__
584#define JAU_FOR_EACH(macro, type, ...) \
585 __VA_OPT__(JAU_EXPAND(JAU_FOR_EACH_HELPER(macro, type, __VA_ARGS__)))
586#define JAU_FOR_EACH_HELPER(macro, type, a1, ...) \
588 __VA_OPT__(JAU_FOR_EACH_AGAIN JAU_PARENS (macro, type, __VA_ARGS__))
589#define JAU_FOR_EACH_AGAIN() JAU_FOR_EACH_HELPER
591#define JAU_ENUM_CASE_SHORT(type, name) case type::name: return #name;
592#define JAU_ENUM_CASE_LONG(type, name) case type::name: return #type "::" #name;
594#define JAU_FOR_EACH_LIST(macro, type, ...) \
595 __VA_OPT__(JAU_EXPAND(JAU_FOR_EACH_LIST_HELPER(macro, type, __VA_ARGS__)))
596#define JAU_FOR_EACH_LIST_HELPER(macro, type, a1, ...) \
598 __VA_OPT__(, JAU_FOR_EACH_LIST_AGAIN JAU_PARENS (macro, type, __VA_ARGS__))
599#define JAU_FOR_EACH_LIST_AGAIN() JAU_FOR_EACH_LIST_HELPER
601#define JAU_ENUM_TYPE_VALUE(type, name) type::name
602#define JAU_ENUM_VALUE(type, name) name
604#define JAU_FOR_EACH_VALUE(macro, type, value, ...) \
605 __VA_OPT__(JAU_EXPAND(JAU_FOR_EACH_VALUE_HELPER(macro, type, value, __VA_ARGS__)))
606#define JAU_FOR_EACH_VALUE_HELPER(macro, type, value, a1, ...) \
607 macro(type, a1, value) \
608 __VA_OPT__(JAU_FOR_EACH_VALUE_AGAIN JAU_PARENS (macro, type, value, __VA_ARGS__))
609#define JAU_FOR_EACH_VALUE_AGAIN() JAU_FOR_EACH_VALUE_HELPER
611#define JAU_MAKE_ENUM_STRING(type, ...) \
612 JAU_MAKE_ENUM_STRING_SUB(type, type, __VA_ARGS__) \
614 constexpr std::string \
615 to_string(const type e) \
616 { return std::string(name(e)); } \
618#define JAU_APPEND_BITSTR(U,V,M) jau::enums::append_bitstr(out, M, U::V, #V, comma);
620#define JAU_MAKE_BITFIELD_ENUM_STRING(type, ...) \
621 JAU_MAKE_ENUM_STRING_SUB(type, type, __VA_ARGS__) \
624 to_string(const type mask) { \
625 std::string out("["); \
626 bool comma = false; \
627 JAU_FOR_EACH_VALUE(JAU_APPEND_BITSTR, type, mask, __VA_ARGS__); \
632#define JAU_MAKE_BITFIELD_ENUM_STRING2(type, stype, ...) \
633 JAU_MAKE_ENUM_STRING_SUB(type, stype, __VA_ARGS__) \
636 to_string(const type mask) { \
637 std::string out("["); \
638 bool comma = false; \
639 JAU_FOR_EACH_VALUE(JAU_APPEND_BITSTR, type, mask, __VA_ARGS__); \
645#define JAU_MAKE_ENUM_STRING_SUB(type, stype, ...) \
646 constexpr std::string_view \
647 long_name(const type v) noexcept \
650 JAU_FOR_EACH(JAU_ENUM_CASE_LONG, type, __VA_ARGS__) \
652 return "undef " #stype; \
655 constexpr std::string_view \
656 name(const type v) noexcept \
659 JAU_FOR_EACH(JAU_ENUM_CASE_SHORT, type, __VA_ARGS__) \
664 constexpr std::string_view \
665 type_name(const type) noexcept \
670#define JAU_MAKE_ENUM_INFO(type, ...) \
671 JAU_MAKE_ENUM_INFO2(type, type, __VA_ARGS__) \
673#define JAU_MAKE_ENUM_INFO2(type, stype, ...) \
674 typedef jau::enums::enum_info<type, JAU_FOR_EACH_LIST(JAU_ENUM_TYPE_VALUE, type, __VA_ARGS__)> stype##_info_t; \
Enumeration info template class including iterator (enum_iterator)
static constexpr size_type size() noexcept
number of all enum values
std::array< value_type, sizeof...(Vargs)> value_array_t
array type for all enum values (value_type), see size()
constexpr const_iterator cbegin() const noexcept
enum_iterator< value_type, Vargs... > const_iterator
enum_iterator to iterate over all enum values (const enum values)
constexpr iterator end() const noexcept
const value_type & reference
reference to value_type
const value_type * pointer
pointer to value_type
constexpr iterator begin() const noexcept
constexpr value_array_t values() const noexcept
constexpr enum_info(const enum_info &o) noexcept=delete
enum_iterator< value_type, Vargs... > iterator
enum_iterator to iterate over all enum values (const enum values)
constexpr std::string_view name() const noexcept
EnumType value_type
enum value type, i.e. the enum type itself
bool enum_info_tag
Used to determine whether this type is an enum_info, see is_enum_info<T>
constexpr const_iterator cend() const noexcept
static constexpr_cxx23 const enum_info & get() noexcept
Enumeration iterator, see enum_info.
constexpr bool operator==(const enum_iterator &rhs) const noexcept
Two way comparison operator, != is implicit, C++20.
constexpr enum_iterator operator--(int) noexcept
Post-decrement.
constexpr iterator_type base() const noexcept
Returns a copy of the underlying storage iterator.
enum_info_t::value_type value_type
constexpr enum_iterator operator++(int) noexcept
Post-increment.
constexpr bool is_begin() const noexcept
Returns true, if this iterator points to begin().
constexpr enum_iterator & operator--() noexcept
Pre-decrement; Well performing, return *this.
constexpr enum_iterator & operator++() noexcept
Pre-increment; Well performing, return *this.
enum_info_t::pointer pointer
constexpr value_type operator*() const noexcept
Dereferencing iterator to value_type reference.
constexpr enum_iterator & operator-=(difference_type i) noexcept
Subtraction-assignment of 'element_count'; Returns *this.
enum_info_t::reference reference
enum_info_t::difference_type difference_type
constexpr enum_iterator & to_end() noexcept
This iterator is set to the last element, end().
constexpr enum_iterator & operator=(enum_iterator &&o) noexcept=default
Assigns identity of given mutable iterator, if they are not identical.
constexpr difference_type dist_end() const noexcept
Returns the distance to_end() using zero as first index.
void swap(enum_iterator &o) noexcept
C++ named requirements: LegacyIterator: Swappable.
std::strong_ordering operator<=>(const enum_iterator &rhs) const noexcept
Three way std::strong_ordering comparison operator, C++20.
constexpr enum_iterator operator-(difference_type rhs) const noexcept
Binary 'iterator - element_count'.
const enum_info_t & description() const noexcept
constexpr value_type operator[](difference_type i) const noexcept
Subscript of 'element_index', returning immutable value_type.
constexpr bool is_end() const noexcept
Returns true, if this iterator points to end().
enum_info_t::size_type size_type
constexpr enum_iterator operator+(difference_type rhs) const noexcept
Binary 'iterator + element_count'.
constexpr difference_type dist_begin() const noexcept
Returns the distance to_begin() using zero as first index.
constexpr enum_iterator(const enum_iterator &o) noexcept=default
C++ named requirements: LegacyIterator: CopyConstructible.
constexpr difference_type operator-(const enum_iterator &rhs) const noexcept
Binary 'iterator - iterator -> element_count'; Returns element_count of type difference_type.
constexpr enum_iterator(enum_iterator &&o) noexcept=default
C++ named requirements: LegacyIterator: MoveConstructable.
constexpr const pointer operator->() const noexcept
Pointer to member access.
constexpr int compare(const enum_iterator &rhs) const noexcept
Returns signum or three-way comparison value.
enum_info< value_type, Vargs... > enum_info_t
constexpr enum_iterator & operator+=(difference_type i) noexcept
Addition-assignment of 'element_count'; Returns *this.
enum_info_t::iterator_base_t iterator_type
constexpr enum_iterator & operator=(const enum_iterator &o) noexcept=default
Assigns content of other mutable iterator to this one, if they are not identical.
constexpr enum_iterator & to_begin() noexcept
This iterator is set to the first element, begin().
consteval_cxx20 std::string_view name() noexcept
constexpr E & operator|=(E &lhs, const E rhs) noexcept
constexpr bool has_any(const E mask, const E bits) noexcept
constexpr std::underlying_type_t< E > number(const E v) noexcept
consteval_cxx20 NameTable< Vargs... > get_names() noexcept
constexpr std::underlying_type_t< E > operator*(const E v) noexcept
constexpr bool operator!=(const E lhs, const E rhs) noexcept
constexpr bool operator==(const E lhs, const E rhs) noexcept
constexpr ValueTable< std::common_type_t< Args... >, sizeof...(Args)> get_values(Args... args) noexcept
constexpr E & operator&=(E &lhs, const E rhs) noexcept
constexpr void append_bitstr(std::string &out, E mask, E bit, const std::string &bitstr, bool &comma)
constexpr bool is_set(const E mask, const E bits) noexcept
std::ostream & operator<<(std::ostream &os, const T v)
constexpr E & operator^=(E &lhs, const E rhs) noexcept
constexpr E operator^(const E lhs, const E rhs) noexcept
constexpr E operator|(const E lhs, const E rhs) noexcept
constexpr E operator&(const E lhs, const E rhs) noexcept
consteval_cxx20 bool is_enum() noexcept
consteval_cxx20 std::string_view long_name() noexcept
constexpr E & write(E &store, const E bits, bool set) noexcept
If set==true, sets the bits in store, i.e.
consteval_cxx20 const char * enum_funcname() noexcept
clang + gcc
constexpr E operator~(const E rhs) noexcept
#define consteval_cxx20
consteval qualifier replacement for C++20 consteval.
const char * type_name() noexcept
Returns the type name of given type T using template Compile Time Type Information (CTTI) only via RT...
Author: Sven Gothel sgothel@jausoft.com Copyright Gothel Software e.K.
Author: Sven Gothel sgothel@jausoft.com Copyright (c) 2024 Gothel Software e.K.
template< class T > is_enum_info<T>::value compile-time Type Trait, determining whether the given tem...