:3
This commit is contained in:
parent
a743cdabe5
commit
bd402f57f5
276 changed files with 37936 additions and 22932 deletions
|
@ -14,63 +14,82 @@
|
|||
#include "../StringLiteral.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace enums {
|
||||
namespace internal {
|
||||
namespace enums {
|
||||
|
||||
template <class EnumType, class LiteralType, size_t N, auto... _enums>
|
||||
struct Names {
|
||||
/// Contains a collection of enums as compile-time strings.
|
||||
using Literal = LiteralType;
|
||||
template <class EnumType, class LiteralType, size_t N, auto... _enums>
|
||||
struct Names {
|
||||
/// Contains a collection of enums as compile-time strings.
|
||||
using Literal = LiteralType;
|
||||
|
||||
/// The number of possible values
|
||||
constexpr static size_t size = N;
|
||||
/// The number of possible values
|
||||
constexpr static size_t size = N;
|
||||
|
||||
/// A list of all the possible enums
|
||||
constexpr static std::array<EnumType, N> enums_ =
|
||||
std::array<EnumType, N>{_enums...};
|
||||
/// A list of all the possible enums
|
||||
constexpr static std::array<EnumType, N> enums_ =
|
||||
std::array<EnumType, N> {_enums...};
|
||||
|
||||
static_assert(N == 0 || LiteralType::size() == N,
|
||||
"Size of literal and enum do not match.");
|
||||
static_assert(N == 0 || LiteralType::size() == N,
|
||||
"Size of literal and enum do not match.");
|
||||
|
||||
template <class NewLiteral, auto _new_enum>
|
||||
using AddOneType = std::conditional_t<
|
||||
N == 0, Names<EnumType, NewLiteral, 1, _new_enum>,
|
||||
Names<EnumType, define_literal_t<LiteralType, NewLiteral>, N + 1,
|
||||
_enums..., _new_enum>>;
|
||||
};
|
||||
template <class NewLiteral, auto _new_enum>
|
||||
using AddOneType =
|
||||
std::conditional_t<N == 0,
|
||||
Names<EnumType, NewLiteral, 1, _new_enum>,
|
||||
Names<EnumType,
|
||||
define_literal_t<LiteralType, NewLiteral>,
|
||||
N + 1,
|
||||
_enums...,
|
||||
_new_enum>>;
|
||||
};
|
||||
|
||||
template <class EnumType, size_t N, StringLiteral... _names, auto... _enums>
|
||||
auto names_to_enumerator_named_tuple(
|
||||
Names<EnumType, Literal<_names...>, N, _enums...>) {
|
||||
return make_named_tuple(Field<_names, EnumType>{_enums}...);
|
||||
}
|
||||
template <class EnumType,
|
||||
size_t N,
|
||||
StringLiteral... _names,
|
||||
auto... _enums>
|
||||
auto names_to_enumerator_named_tuple(
|
||||
Names<EnumType, Literal<_names...>, N, _enums...>) {
|
||||
return make_named_tuple(Field<_names, EnumType> {_enums}...);
|
||||
}
|
||||
|
||||
template <class EnumType, size_t N, StringLiteral... _names, auto... _enums>
|
||||
auto names_to_underlying_enumerator_named_tuple(
|
||||
Names<EnumType, Literal<_names...>, N, _enums...>) {
|
||||
return make_named_tuple(Field<_names, std::underlying_type_t<EnumType>>{
|
||||
static_cast<std::underlying_type_t<EnumType>>(_enums)}...);
|
||||
}
|
||||
template <class EnumType,
|
||||
size_t N,
|
||||
StringLiteral... _names,
|
||||
auto... _enums>
|
||||
auto names_to_underlying_enumerator_named_tuple(
|
||||
Names<EnumType, Literal<_names...>, N, _enums...>) {
|
||||
return make_named_tuple(
|
||||
Field<_names, std::underlying_type_t<EnumType>> {
|
||||
static_cast<std::underlying_type_t<EnumType>>(_enums)}...);
|
||||
}
|
||||
|
||||
template <class EnumType, size_t N, StringLiteral... _names, auto... _enums>
|
||||
constexpr std::array<std::pair<std::string_view, EnumType>, N>
|
||||
names_to_enumerator_array(Names<EnumType, Literal<_names...>, N, _enums...>) {
|
||||
return {
|
||||
std::make_pair(LiteralHelper<_names>::field_.string_view(), _enums)...};
|
||||
}
|
||||
template <class EnumType,
|
||||
size_t N,
|
||||
StringLiteral... _names,
|
||||
auto... _enums>
|
||||
constexpr std::array<std::pair<std::string_view, EnumType>, N>
|
||||
names_to_enumerator_array(
|
||||
Names<EnumType, Literal<_names...>, N, _enums...>) {
|
||||
return {std::make_pair(LiteralHelper<_names>::field_.string_view(),
|
||||
_enums)...};
|
||||
}
|
||||
|
||||
template <class EnumType, size_t N, StringLiteral... _names, auto... _enums>
|
||||
constexpr std::array<
|
||||
std::pair<std::string_view, std::underlying_type_t<EnumType>>, N>
|
||||
names_to_underlying_enumerator_array(
|
||||
Names<EnumType, Literal<_names...>, N, _enums...>) {
|
||||
return {
|
||||
std::make_pair(LiteralHelper<_names>::field_.string_view(),
|
||||
static_cast<std::underlying_type_t<EnumType>>(_enums))...};
|
||||
}
|
||||
template <class EnumType,
|
||||
size_t N,
|
||||
StringLiteral... _names,
|
||||
auto... _enums>
|
||||
constexpr std::array<
|
||||
std::pair<std::string_view, std::underlying_type_t<EnumType>>,
|
||||
N>
|
||||
names_to_underlying_enumerator_array(
|
||||
Names<EnumType, Literal<_names...>, N, _enums...>) {
|
||||
return {std::make_pair(
|
||||
LiteralHelper<_names>::field_.string_view(),
|
||||
static_cast<std::underlying_type_t<EnumType>>(_enums))...};
|
||||
}
|
||||
|
||||
} // namespace enums
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
} // namespace enums
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -15,118 +15,121 @@
|
|||
#include "is_flag_enum.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace enums {
|
||||
namespace internal {
|
||||
namespace enums {
|
||||
|
||||
template <class EnumType>
|
||||
class StringConverter {
|
||||
public:
|
||||
static constexpr bool is_flag_enum_ = is_flag_enum<EnumType>;
|
||||
template <class EnumType>
|
||||
class StringConverter {
|
||||
public:
|
||||
static constexpr bool is_flag_enum_ = is_flag_enum<EnumType>;
|
||||
|
||||
static constexpr auto names_ = get_enum_names<EnumType, is_flag_enum_>();
|
||||
static constexpr auto names_ =
|
||||
get_enum_names<EnumType, is_flag_enum_>();
|
||||
|
||||
using NamesLiteral = typename decltype(names_)::Literal;
|
||||
using NamesLiteral = typename decltype(names_)::Literal;
|
||||
|
||||
public:
|
||||
/// Transform an enum to a matching string.
|
||||
static std::string enum_to_string(const EnumType _enum) {
|
||||
if constexpr (is_flag_enum_) {
|
||||
return flag_enum_to_string(_enum);
|
||||
} else {
|
||||
return enum_to_single_string(_enum);
|
||||
}
|
||||
}
|
||||
public:
|
||||
/// Transform an enum to a matching string.
|
||||
static std::string enum_to_string(const EnumType _enum) {
|
||||
if constexpr (is_flag_enum_) {
|
||||
return flag_enum_to_string(_enum);
|
||||
} else {
|
||||
return enum_to_single_string(_enum);
|
||||
}
|
||||
}
|
||||
|
||||
/// Transforms a string to the matching enum.
|
||||
static Result<EnumType> string_to_enum(const std::string& _str) {
|
||||
static_assert(names_.size != 0,
|
||||
"No enum could be identified. Please choose enum values "
|
||||
"between 0 to 127 or for flag enums choose 1,2,4,8,16,...");
|
||||
if constexpr (is_flag_enum_) {
|
||||
return string_to_flag_enum(_str);
|
||||
} else {
|
||||
return single_string_to_enum(_str);
|
||||
}
|
||||
}
|
||||
/// Transforms a string to the matching enum.
|
||||
static Result<EnumType> string_to_enum(const std::string& _str) {
|
||||
static_assert(
|
||||
names_.size != 0,
|
||||
"No enum could be identified. Please choose enum values "
|
||||
"between 0 to 127 or for flag enums choose 1,2,4,8,16,...");
|
||||
if constexpr (is_flag_enum_) {
|
||||
return string_to_flag_enum(_str);
|
||||
} else {
|
||||
return single_string_to_enum(_str);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
/// Iterates through the enum bit by bit and matches it against the flags.
|
||||
static std::string flag_enum_to_string(const EnumType _e) {
|
||||
using T = std::underlying_type_t<EnumType>;
|
||||
auto val = static_cast<T>(_e);
|
||||
int i = 0;
|
||||
std::vector<std::string> flags;
|
||||
while (val != 0) {
|
||||
const auto bit = val & static_cast<T>(1);
|
||||
if (bit == 1) {
|
||||
auto str = enum_to_single_string(
|
||||
static_cast<EnumType>(static_cast<T>(1) << i));
|
||||
flags.emplace_back(std::move(str));
|
||||
}
|
||||
++i;
|
||||
val >>= 1;
|
||||
}
|
||||
return strings::join("|", flags);
|
||||
}
|
||||
private:
|
||||
/// Iterates through the enum bit by bit and matches it against the
|
||||
/// flags.
|
||||
static std::string flag_enum_to_string(const EnumType _e) {
|
||||
using T = std::underlying_type_t<EnumType>;
|
||||
auto val = static_cast<T>(_e);
|
||||
int i = 0;
|
||||
std::vector<std::string> flags;
|
||||
while (val != 0) {
|
||||
const auto bit = val & static_cast<T>(1);
|
||||
if (bit == 1) {
|
||||
auto str = enum_to_single_string(
|
||||
static_cast<EnumType>(static_cast<T>(1) << i));
|
||||
flags.emplace_back(std::move(str));
|
||||
}
|
||||
++i;
|
||||
val >>= 1;
|
||||
}
|
||||
return strings::join("|", flags);
|
||||
}
|
||||
|
||||
/// This assumes that _enum can be exactly matched to one of the names and
|
||||
/// does not have to be combined using |.
|
||||
static std::string enum_to_single_string(const EnumType _enum) {
|
||||
const auto to_str = [](const auto _l) { return _l.str(); };
|
||||
/// This assumes that _enum can be exactly matched to one of the names
|
||||
/// and does not have to be combined using |.
|
||||
static std::string enum_to_single_string(const EnumType _enum) {
|
||||
const auto to_str = [](const auto _l) { return _l.str(); };
|
||||
|
||||
for (size_t i = 0; i < names_.size; ++i) {
|
||||
if (names_.enums_[i] == _enum) {
|
||||
return NamesLiteral::from_value(
|
||||
static_cast<typename NamesLiteral::ValueType>(i))
|
||||
.transform(to_str)
|
||||
.value();
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < names_.size; ++i) {
|
||||
if (names_.enums_[i] == _enum) {
|
||||
return NamesLiteral::from_value(
|
||||
static_cast<typename NamesLiteral::ValueType>(i))
|
||||
.transform(to_str)
|
||||
.value();
|
||||
}
|
||||
}
|
||||
|
||||
return std::to_string(static_cast<std::underlying_type_t<EnumType>>(_enum));
|
||||
}
|
||||
return std::to_string(
|
||||
static_cast<std::underlying_type_t<EnumType>>(_enum));
|
||||
}
|
||||
|
||||
/// Finds the enum matching the literal.
|
||||
static EnumType literal_to_enum(const NamesLiteral _lit) noexcept {
|
||||
return names_.enums_[_lit.value()];
|
||||
}
|
||||
/// Finds the enum matching the literal.
|
||||
static EnumType literal_to_enum(const NamesLiteral _lit) noexcept {
|
||||
return names_.enums_[_lit.value()];
|
||||
}
|
||||
|
||||
/// This assumes that _enum can be exactly matched to one of the names and
|
||||
/// does not have to be combined using |.
|
||||
static Result<EnumType> single_string_to_enum(const std::string& _str) {
|
||||
const auto r = NamesLiteral::from_string(_str).transform(literal_to_enum);
|
||||
if (r) {
|
||||
return r;
|
||||
} else {
|
||||
try {
|
||||
return static_cast<EnumType>(std::stoi(_str));
|
||||
} catch (std::exception& exp) {
|
||||
return Error(exp.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
/// This assumes that _enum can be exactly matched to one of the names
|
||||
/// and does not have to be combined using |.
|
||||
static Result<EnumType> single_string_to_enum(const std::string& _str) {
|
||||
const auto r =
|
||||
NamesLiteral::from_string(_str).transform(literal_to_enum);
|
||||
if (r) {
|
||||
return r;
|
||||
} else {
|
||||
try {
|
||||
return static_cast<EnumType>(std::stoi(_str));
|
||||
} catch (std::exception& exp) { return Error(exp.what()); }
|
||||
}
|
||||
}
|
||||
|
||||
/// Only relevant if this is a flag enum - combines the different matches
|
||||
/// using |.
|
||||
static Result<EnumType> string_to_flag_enum(
|
||||
const std::string& _str) noexcept {
|
||||
using T = std::underlying_type_t<EnumType>;
|
||||
const auto split = strings::split(_str, "|");
|
||||
auto res = static_cast<T>(0);
|
||||
for (const auto& s : split) {
|
||||
const auto r = single_string_to_enum(s);
|
||||
if (r) {
|
||||
res |= static_cast<T>(*r);
|
||||
} else {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
return static_cast<EnumType>(res);
|
||||
}
|
||||
};
|
||||
/// Only relevant if this is a flag enum - combines the different
|
||||
/// matches using |.
|
||||
static Result<EnumType> string_to_flag_enum(
|
||||
const std::string& _str) noexcept {
|
||||
using T = std::underlying_type_t<EnumType>;
|
||||
const auto split = strings::split(_str, "|");
|
||||
auto res = static_cast<T>(0);
|
||||
for (const auto& s : split) {
|
||||
const auto r = single_string_to_enum(s);
|
||||
if (r) {
|
||||
res |= static_cast<T>(*r);
|
||||
} else {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
return static_cast<EnumType>(res);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace enums
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
} // namespace enums
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -36,116 +36,127 @@
|
|||
// defined.
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace enums {
|
||||
namespace internal {
|
||||
namespace enums {
|
||||
|
||||
template <auto e>
|
||||
consteval auto get_enum_name_str_view() {
|
||||
// Unfortunately, we cannot avoid the use of a compiler-specific macro for
|
||||
// Clang on Windows. For all other compilers, function_name works as intended.
|
||||
template <auto e>
|
||||
consteval auto get_enum_name_str_view() {
|
||||
// Unfortunately, we cannot avoid the use of a compiler-specific macro
|
||||
// for Clang on Windows. For all other compilers, function_name works as
|
||||
// intended.
|
||||
#if defined(__clang__) && defined(_MSC_VER)
|
||||
const auto func_name = std::string_view{__PRETTY_FUNCTION__};
|
||||
const auto func_name = std::string_view {__PRETTY_FUNCTION__};
|
||||
#else
|
||||
const auto func_name =
|
||||
std::string_view{std::source_location::current().function_name()};
|
||||
const auto func_name =
|
||||
std::string_view {std::source_location::current().function_name()};
|
||||
#endif
|
||||
#if defined(__clang__)
|
||||
const auto split = func_name.substr(0, func_name.size() - 1);
|
||||
return split.substr(split.find("e = ") + 4);
|
||||
const auto split = func_name.substr(0, func_name.size() - 1);
|
||||
return split.substr(split.find("e = ") + 4);
|
||||
#elif defined(__GNUC__)
|
||||
const auto split = func_name.substr(0, func_name.size() - 1);
|
||||
return split.substr(split.find("e = ") + 4);
|
||||
const auto split = func_name.substr(0, func_name.size() - 1);
|
||||
return split.substr(split.find("e = ") + 4);
|
||||
#elif defined(_MSC_VER)
|
||||
const auto split = func_name.substr(0, func_name.size() - 7);
|
||||
return split.substr(split.find("get_enum_name_str_view<") + 23);
|
||||
const auto split = func_name.substr(0, func_name.size() - 7);
|
||||
return split.substr(split.find("get_enum_name_str_view<") + 23);
|
||||
#else
|
||||
static_assert(false,
|
||||
"You are using an unsupported compiler. Please use GCC, Clang "
|
||||
"or MSVC or use rfl::Literal.");
|
||||
static_assert(
|
||||
false,
|
||||
"You are using an unsupported compiler. Please use GCC, Clang "
|
||||
"or MSVC or use rfl::Literal.");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
template <auto e>
|
||||
consteval auto get_enum_name() {
|
||||
constexpr auto name = get_enum_name_str_view<e>();
|
||||
const auto to_str_lit = [&]<auto... Ns>(std::index_sequence<Ns...>) {
|
||||
return StringLiteral<sizeof...(Ns) + 1>{name[Ns]...};
|
||||
};
|
||||
return to_str_lit(std::make_index_sequence<name.size()>{});
|
||||
}
|
||||
template <auto e>
|
||||
consteval auto get_enum_name() {
|
||||
constexpr auto name = get_enum_name_str_view<e>();
|
||||
const auto to_str_lit = [&]<auto... Ns>(std::index_sequence<Ns...>) {
|
||||
return StringLiteral<sizeof...(Ns) + 1> {name[Ns]...};
|
||||
};
|
||||
return to_str_lit(std::make_index_sequence<name.size()> {});
|
||||
}
|
||||
|
||||
template <class T>
|
||||
consteval T calc_greatest_power_of_two() {
|
||||
if constexpr (std::is_signed_v<T>) {
|
||||
return static_cast<T>(1) << (sizeof(T) * 8 - 2);
|
||||
} else {
|
||||
return static_cast<T>(1) << (sizeof(T) * 8 - 1);
|
||||
}
|
||||
}
|
||||
template <class T>
|
||||
consteval T calc_greatest_power_of_two() {
|
||||
if constexpr (std::is_signed_v<T>) {
|
||||
return static_cast<T>(1) << (sizeof(T) * 8 - 2);
|
||||
} else {
|
||||
return static_cast<T>(1) << (sizeof(T) * 8 - 1);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T, bool _is_flag>
|
||||
consteval T get_max() {
|
||||
if constexpr (_is_flag) {
|
||||
return calc_greatest_power_of_two<T>();
|
||||
} else {
|
||||
return std::numeric_limits<T>::max() > 127 ? static_cast<T>(127)
|
||||
: std::numeric_limits<T>::max();
|
||||
}
|
||||
}
|
||||
template <class T, bool _is_flag>
|
||||
consteval T get_max() {
|
||||
if constexpr (_is_flag) {
|
||||
return calc_greatest_power_of_two<T>();
|
||||
} else {
|
||||
return std::numeric_limits<T>::max() > 127
|
||||
? static_cast<T>(127)
|
||||
: std::numeric_limits<T>::max();
|
||||
}
|
||||
}
|
||||
|
||||
template <class T, bool _is_flag, int _i>
|
||||
consteval T calc_j() {
|
||||
if constexpr (_is_flag) {
|
||||
return static_cast<T>(1) << _i;
|
||||
} else {
|
||||
return static_cast<T>(_i);
|
||||
}
|
||||
}
|
||||
template <class T, bool _is_flag, int _i>
|
||||
consteval T calc_j() {
|
||||
if constexpr (_is_flag) {
|
||||
return static_cast<T>(1) << _i;
|
||||
} else {
|
||||
return static_cast<T>(_i);
|
||||
}
|
||||
}
|
||||
|
||||
template <class EnumType, class NamesType, auto _max, bool _is_flag, int _i>
|
||||
consteval auto get_enum_names_impl() {
|
||||
using T = std::underlying_type_t<EnumType>;
|
||||
template <class EnumType,
|
||||
class NamesType,
|
||||
auto _max,
|
||||
bool _is_flag,
|
||||
int _i>
|
||||
consteval auto get_enum_names_impl() {
|
||||
using T = std::underlying_type_t<EnumType>;
|
||||
|
||||
constexpr T j = calc_j<T, _is_flag, _i>();
|
||||
constexpr T j = calc_j<T, _is_flag, _i>();
|
||||
|
||||
constexpr auto name = get_enum_name<static_cast<EnumType>(j)>();
|
||||
constexpr auto name = get_enum_name<static_cast<EnumType>(j)>();
|
||||
|
||||
if constexpr (std::get<0>(name.arr_) == '(') {
|
||||
if constexpr (j == _max) {
|
||||
return NamesType{};
|
||||
} else {
|
||||
return get_enum_names_impl<EnumType, NamesType, _max, _is_flag, _i + 1>();
|
||||
}
|
||||
} else {
|
||||
using NewNames = typename NamesType::template AddOneType<
|
||||
Literal<remove_namespaces<name>()>, static_cast<EnumType>(j)>;
|
||||
if constexpr (std::get<0>(name.arr_) == '(') {
|
||||
if constexpr (j == _max) {
|
||||
return NamesType {};
|
||||
} else {
|
||||
return get_enum_names_impl<EnumType, NamesType, _max, _is_flag,
|
||||
_i + 1>();
|
||||
}
|
||||
} else {
|
||||
using NewNames = typename NamesType::template AddOneType<
|
||||
Literal<remove_namespaces<name>()>, static_cast<EnumType>(j)>;
|
||||
|
||||
if constexpr (j == _max) {
|
||||
return NewNames{};
|
||||
} else {
|
||||
return get_enum_names_impl<EnumType, NewNames, _max, _is_flag, _i + 1>();
|
||||
}
|
||||
}
|
||||
}
|
||||
if constexpr (j == _max) {
|
||||
return NewNames {};
|
||||
} else {
|
||||
return get_enum_names_impl<EnumType, NewNames, _max, _is_flag,
|
||||
_i + 1>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class EnumType, bool _is_flag>
|
||||
consteval auto get_enum_names() {
|
||||
static_assert(is_scoped_enum<EnumType>,
|
||||
"You must use scoped enums (using class or struct) for the "
|
||||
"parsing to work!");
|
||||
template <class EnumType, bool _is_flag>
|
||||
consteval auto get_enum_names() {
|
||||
static_assert(
|
||||
is_scoped_enum<EnumType>,
|
||||
"You must use scoped enums (using class or struct) for the "
|
||||
"parsing to work!");
|
||||
|
||||
static_assert(std::is_integral_v<std::underlying_type_t<EnumType>>,
|
||||
"The underlying type of any Enum must be integral!");
|
||||
static_assert(std::is_integral_v<std::underlying_type_t<EnumType>>,
|
||||
"The underlying type of any Enum must be integral!");
|
||||
|
||||
constexpr auto max = get_max<std::underlying_type_t<EnumType>, _is_flag>();
|
||||
constexpr auto max =
|
||||
get_max<std::underlying_type_t<EnumType>, _is_flag>();
|
||||
|
||||
using EmptyNames = Names<EnumType, rfl::Literal<"">, 0>;
|
||||
using EmptyNames = Names<EnumType, rfl::Literal<"">, 0>;
|
||||
|
||||
return get_enum_names_impl<EnumType, EmptyNames, max, _is_flag, 0>();
|
||||
}
|
||||
return get_enum_names_impl<EnumType, EmptyNames, max, _is_flag, 0>();
|
||||
}
|
||||
|
||||
} // namespace enums
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
} // namespace enums
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -6,17 +6,17 @@
|
|||
#include "is_scoped_enum.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace enums {
|
||||
namespace internal {
|
||||
namespace enums {
|
||||
|
||||
template <class EnumType>
|
||||
concept is_flag_enum = is_scoped_enum<EnumType> &&
|
||||
requires(EnumType e1, EnumType e2) {
|
||||
{ e1 | e2 } -> std::same_as<EnumType>;
|
||||
};
|
||||
template <class EnumType>
|
||||
concept is_flag_enum =
|
||||
is_scoped_enum<EnumType> && requires(EnumType e1, EnumType e2) {
|
||||
{ e1 | e2 } -> std::same_as<EnumType>;
|
||||
};
|
||||
|
||||
} // namespace enums
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
} // namespace enums
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -5,15 +5,16 @@
|
|||
#include <type_traits>
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace enums {
|
||||
namespace internal {
|
||||
namespace enums {
|
||||
|
||||
template <class EnumType>
|
||||
concept is_scoped_enum = std::is_enum_v<EnumType> &&
|
||||
!std::is_convertible_v<EnumType, std::underlying_type_t<EnumType>>;
|
||||
template <class EnumType>
|
||||
concept is_scoped_enum =
|
||||
std::is_enum_v<EnumType> &&
|
||||
!std::is_convertible_v<EnumType, std::underlying_type_t<EnumType>>;
|
||||
|
||||
} // namespace enums
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
} // namespace enums
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue