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 bool has_any(
const E mask)
noexcept {
245 return std::underlying_type_t<E>(0) != ( *mask );
248 template<
typename E, std::enable_if_t<std::is_enum_v<E>>* =
nullptr>
249 constexpr void append_bitstr(std::string& out, E mask, E bit,
const std::string& bitstr,
bool& comma) {
250 if( bit == (mask & bit) ) {
251 if( comma ) { out.append(
", "); }
252 out.append(bitstr); comma =
true;
256 template <
typename T,
257 std::enable_if_t<std::is_enum_v<T>>* =
nullptr>
260 template <
typename EnumType,
auto... Vargs>
class enum_iterator;
265 template <
typename EnumType,
auto... Vargs>
296 constexpr iterator_base_t begin_iter() const noexcept {
return &values_[0]; }
297 constexpr iterator_base_t end_iter() const noexcept {
return &values_[0] +
size(); }
301 : values_({{ Vargs... }})
305 constexpr enum_info(
const enum_info& o)
noexcept =
delete;
308 static enum_info singleton;
326 template<
class,
class =
void >
336 template <typename enum_info_t, std::enable_if_t<is_enum_info<enum_info_t>::value>* =
nullptr>
337 inline std::ostream&
operator<<(std::ostream&
os,
const enum_info_t& v) {
338 os << v.name() <<
"[";
339 typename enum_info_t::iterator end = v.end();
341 for(
typename enum_info_t::iterator iter = v.begin(); iter != end; ++iter, comma=
true) {
342 typename enum_info_t::value_type ev = *iter;
346 os << ev <<
" (" << std::to_string( *ev ) <<
")";
355 template <
typename EnumType,
auto... Vargs>
356 class enum_iterator {
378 friend class enum_info<EnumType, Vargs...>;
381 : info_(info), iterator_(iter)
399 constexpr enum_iterator&
operator=(
const enum_iterator& o)
noexcept =
default;
416 constexpr enum_iterator&
operator=(enum_iterator&& o)
noexcept =
default;
423 void swap(enum_iterator& o)
noexcept {
424 std::swap( info_, o.info_);
425 std::swap( iterator_, o.iterator_);
436 constexpr bool is_end() const noexcept {
return iterator_ == info_.end_iter(); }
441 constexpr enum_iterator&
to_end() noexcept
442 { iterator_ = info_.end_iter();
return *
this; }
452 constexpr bool is_begin() const noexcept {
return iterator_ == info_.begin_iter(); }
458 { iterator_ = info_.begin_iter();
return *
this; }
477 constexpr int compare(
const enum_iterator& rhs)
const noexcept {
478 return iterator_ == rhs.iterator_ ? 0
479 : ( iterator_ < rhs.iterator_ ? -1 : 1);
483 constexpr bool operator==(
const enum_iterator& rhs)
const noexcept
484 {
return iterator_ == rhs.iterator_; }
487 std::strong_ordering
operator<=>(
const enum_iterator& rhs)
const noexcept {
488 return iterator_ == rhs.iterator_ ? std::strong_ordering::equal :
489 ( iterator_ < rhs.iterator_ ? std::strong_ordering::less : std::strong_ordering::greater );
507 return &(*iterator_);
518 {
return enum_iterator(info_, iterator_++); }
530 {
return enum_iterator(info_, iterator_--); }
536 {
return iterator_[i]; }
540 { iterator_ += i;
return *
this; }
544 {
return enum_iterator(info_, iterator_ + rhs); }
548 { iterator_ -= i;
return *
this; }
552 {
return enum_iterator(info_, iterator_ - rhs); }
558 {
return iterator_ - rhs.iterator_; }
580#define JAU_EXPAND(...) JAU_EXPAND4(JAU_EXPAND4(JAU_EXPAND4(JAU_EXPAND4(__VA_ARGS__))))
581#define JAU_EXPAND4(...) JAU_EXPAND3(JAU_EXPAND3(JAU_EXPAND3(JAU_EXPAND3(__VA_ARGS__))))
582#define JAU_EXPAND3(...) JAU_EXPAND2(JAU_EXPAND2(JAU_EXPAND2(JAU_EXPAND2(__VA_ARGS__))))
583#define JAU_EXPAND2(...) JAU_EXPAND1(JAU_EXPAND1(JAU_EXPAND1(JAU_EXPAND1(__VA_ARGS__))))
584#define JAU_EXPAND1(...) __VA_ARGS__
586#define JAU_FOR_EACH(macro, type, ...) \
587 __VA_OPT__(JAU_EXPAND(JAU_FOR_EACH_HELPER(macro, type, __VA_ARGS__)))
588#define JAU_FOR_EACH_HELPER(macro, type, a1, ...) \
590 __VA_OPT__(JAU_FOR_EACH_AGAIN JAU_PARENS (macro, type, __VA_ARGS__))
591#define JAU_FOR_EACH_AGAIN() JAU_FOR_EACH_HELPER
593#define JAU_ENUM_CASE_SHORT(type, name) case type::name: return #name;
594#define JAU_ENUM_CASE_LONG(type, name) case type::name: return #type "::" #name;
596#define JAU_FOR_EACH_LIST(macro, type, ...) \
597 __VA_OPT__(JAU_EXPAND(JAU_FOR_EACH_LIST_HELPER(macro, type, __VA_ARGS__)))
598#define JAU_FOR_EACH_LIST_HELPER(macro, type, a1, ...) \
600 __VA_OPT__(, JAU_FOR_EACH_LIST_AGAIN JAU_PARENS (macro, type, __VA_ARGS__))
601#define JAU_FOR_EACH_LIST_AGAIN() JAU_FOR_EACH_LIST_HELPER
603#define JAU_ENUM_TYPE_VALUE(type, name) type::name
604#define JAU_ENUM_VALUE(type, name) name
606#define JAU_FOR_EACH_VALUE(macro, type, value, ...) \
607 __VA_OPT__(JAU_EXPAND(JAU_FOR_EACH_VALUE_HELPER(macro, type, value, __VA_ARGS__)))
608#define JAU_FOR_EACH_VALUE_HELPER(macro, type, value, a1, ...) \
609 macro(type, a1, value) \
610 __VA_OPT__(JAU_FOR_EACH_VALUE_AGAIN JAU_PARENS (macro, type, value, __VA_ARGS__))
611#define JAU_FOR_EACH_VALUE_AGAIN() JAU_FOR_EACH_VALUE_HELPER
613#define JAU_MAKE_ENUM_STRING(type, ...) \
614 JAU_MAKE_ENUM_STRING_SUB(type, type, __VA_ARGS__) \
616 constexpr std::string \
617 to_string(const type e) noexcept \
618 { return std::string(name(e)); } \
620#define JAU_APPEND_BITSTR(U,V,M) jau::enums::append_bitstr(out, M, U::V, #V, comma);
622#define JAU_MAKE_BITFIELD_ENUM_STRING(type, ...) \
623 JAU_MAKE_ENUM_STRING_SUB(type, type, __VA_ARGS__) \
626 to_string(const type mask) noexcept { \
627 std::string out("["); \
628 bool comma = false; \
629 JAU_FOR_EACH_VALUE(JAU_APPEND_BITSTR, type, mask, __VA_ARGS__); \
634#define JAU_MAKE_BITFIELD_ENUM_STRING2(type, stype, ...) \
635 JAU_MAKE_ENUM_STRING_SUB(type, stype, __VA_ARGS__) \
638 to_string(const type mask) noexcept { \
639 std::string out("["); \
640 bool comma = false; \
641 JAU_FOR_EACH_VALUE(JAU_APPEND_BITSTR, type, mask, __VA_ARGS__); \
647#define JAU_MAKE_ENUM_STRING_SUB(type, stype, ...) \
648 constexpr std::string_view \
649 long_name(const type v) noexcept \
652 JAU_FOR_EACH(JAU_ENUM_CASE_LONG, type, __VA_ARGS__) \
654 return "undef " #stype; \
657 constexpr std::string_view \
658 name(const type v) noexcept \
661 JAU_FOR_EACH(JAU_ENUM_CASE_SHORT, type, __VA_ARGS__) \
666 constexpr std::string_view \
667 type_name(const type) noexcept \
673#define JAU_MAKE_ENUM_STRING_MEMBER(type, ...) \
674 JAU_MAKE_ENUM_STRING_SUB_MEMBER(type, type, __VA_ARGS__) \
676 constexpr static std::string \
677 to_string(const type e) noexcept \
678 { return std::string(name(e)); } \
681#define JAU_MAKE_BITFIELD_ENUM_STRING_MEMBER(type, ...) \
682 JAU_MAKE_ENUM_STRING_SUB_MEMBER(type, type, __VA_ARGS__) \
684 inline static std::string \
685 to_string(const type mask) noexcept { \
686 std::string out("["); \
687 bool comma = false; \
688 JAU_FOR_EACH_VALUE(JAU_APPEND_BITSTR, type, mask, __VA_ARGS__); \
694#define JAU_MAKE_ENUM_STRING_SUB_MEMBER(type, stype, ...) \
695 constexpr static std::string_view \
696 long_name(const type v) noexcept \
699 JAU_FOR_EACH(JAU_ENUM_CASE_LONG, type, __VA_ARGS__) \
701 return "undef " #stype; \
704 constexpr static std::string_view \
705 name(const type v) noexcept \
708 JAU_FOR_EACH(JAU_ENUM_CASE_SHORT, type, __VA_ARGS__) \
713 constexpr static std::string_view \
714 type_name(const type) noexcept \
719#define JAU_MAKE_ENUM_INFO(type, ...) \
720 JAU_MAKE_ENUM_INFO2(type, type, __VA_ARGS__) \
722#define JAU_MAKE_ENUM_INFO2(type, stype, ...) \
723 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...