mirror of
https://github.com/aantron/better-enums.git
synced 2025-12-06 16:56:42 +08:00
Made basic interface constexpr and made default cast checked.
This commit is contained in:
parent
2127b89dd4
commit
f55d2b56dc
6
Enum.h
6
Enum.h
@ -11,7 +11,6 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
// TODO toUnderlying can probably be constexpr.
|
|
||||||
// TODO Consider using a traits type instead of prefixing static members with an
|
// TODO Consider using a traits type instead of prefixing static members with an
|
||||||
// underscore.
|
// underscore.
|
||||||
// TODO Make appropriate changes in naming in EnumInternal.h. Most especially,
|
// TODO Make appropriate changes in naming in EnumInternal.h. Most especially,
|
||||||
@ -19,13 +18,8 @@
|
|||||||
// TODO Make the default cast checked.
|
// TODO Make the default cast checked.
|
||||||
// TODO Create explicit members that do everything the constructors and
|
// TODO Create explicit members that do everything the constructors and
|
||||||
// operators do, and define the operators in terms of those.
|
// operators do, and define the operators in terms of those.
|
||||||
// TODO Remove implicit conversion to underlying type.
|
|
||||||
// TODO Rename Underlying so it doesn't clash with any value names.
|
|
||||||
// TODO _first, _last, _count.
|
// TODO _first, _last, _count.
|
||||||
// TODO Try to make names and values into values instead of functions.
|
// TODO Try to make names and values into values instead of functions.
|
||||||
// TODO Move the member value into the base class and define most functions
|
|
||||||
// there.
|
|
||||||
// TODO Make sure to cast to the underlying type in to_int.
|
|
||||||
|
|
||||||
#define ENUM(EnumType, UnderlyingType, ...) \
|
#define ENUM(EnumType, UnderlyingType, ...) \
|
||||||
_ENUM_ARRAYS(EnumType, UnderlyingType, __VA_ARGS__); \
|
_ENUM_ARRAYS(EnumType, UnderlyingType, __VA_ARGS__); \
|
||||||
|
|||||||
134
EnumInternal.h
134
EnumInternal.h
@ -39,6 +39,7 @@
|
|||||||
/// are very likely to collide.
|
/// are very likely to collide.
|
||||||
|
|
||||||
// TODO Make it possible for enums to be map keys.
|
// TODO Make it possible for enums to be map keys.
|
||||||
|
// TODO Rename internal functions to match public interface conventions.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -295,6 +296,11 @@ constexpr bool _endsName(char c, size_t index = 0)
|
|||||||
_endsName(c, index + 1);
|
_endsName(c, index + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr char _toLowercaseAscii(char c)
|
||||||
|
{
|
||||||
|
return c >= 0x41 && c <= 0x5A ? c + 0x20 : c;
|
||||||
|
}
|
||||||
|
|
||||||
/// Compile-time function that matches a stringized name (with potential
|
/// Compile-time function that matches a stringized name (with potential
|
||||||
/// trailing spaces and equals signs) against a reference name (a regular
|
/// trailing spaces and equals signs) against a reference name (a regular
|
||||||
/// null-terminated string).
|
/// null-terminated string).
|
||||||
@ -327,6 +333,20 @@ constexpr bool _namesMatch(const char *stringizedName,
|
|||||||
_namesMatch(stringizedName, referenceName, index + 1);
|
_namesMatch(stringizedName, referenceName, index + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr bool _namesMatchNocase(const char *stringizedName,
|
||||||
|
const char *referenceName,
|
||||||
|
size_t index = 0)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
_endsName(stringizedName[index]) ? referenceName[index] == '\0' :
|
||||||
|
referenceName[index] == '\0' ? false :
|
||||||
|
_toLowercaseAscii(stringizedName[index]) !=
|
||||||
|
_toLowercaseAscii(referenceName[index]) ? false :
|
||||||
|
_namesMatchNocase(stringizedName, referenceName, index + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define _ENUM_NOT_FOUND ((size_t)-1)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// Functions and types used to compute range properties such as the minimum and
|
/// Functions and types used to compute range properties such as the minimum and
|
||||||
@ -456,7 +476,7 @@ static inline const char * const* _processNames(const char * const *rawNames,
|
|||||||
|
|
||||||
template <typename EnumType> class _GeneratedArrays;
|
template <typename EnumType> class _GeneratedArrays;
|
||||||
|
|
||||||
// TODO Try to convert values array to _Enumerated[] instead of _Integral[].
|
// TODO Move definitions to last macro.
|
||||||
|
|
||||||
#define _ENUM_ARRAYS(EnumType, UnderlyingType, ...) \
|
#define _ENUM_ARRAYS(EnumType, UnderlyingType, ...) \
|
||||||
class EnumType; \
|
class EnumType; \
|
||||||
@ -518,13 +538,16 @@ class _Implementation : public _GeneratedArrays<EnumType> {
|
|||||||
return _value;
|
return _value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO This should be a checked cast.
|
|
||||||
constexpr static EnumType _from_int(_Integral value)
|
constexpr static EnumType _from_int(_Integral value)
|
||||||
|
{
|
||||||
|
return _value_array[_from_int_loop(value, true)];
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr static EnumType _from_int_unchecked(_Integral value)
|
||||||
{
|
{
|
||||||
return (_Enumerated)value;
|
return (_Enumerated)value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Use iterables.
|
|
||||||
const char* to_string() const
|
const char* to_string() const
|
||||||
{
|
{
|
||||||
_processNames();
|
_processNames();
|
||||||
@ -537,30 +560,29 @@ class _Implementation : public _GeneratedArrays<EnumType> {
|
|||||||
throw std::domain_error("Enum::_to_string: invalid enum value");
|
throw std::domain_error("Enum::_to_string: invalid enum value");
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Make constexpr.
|
constexpr static EnumType _from_string(const char *name)
|
||||||
static EnumType _from_string(const char *name)
|
|
||||||
{
|
{
|
||||||
_processNames();
|
return _value_array[_from_string_loop(name, true)];
|
||||||
|
|
||||||
for (size_t index = 0; index < _size; ++index) {
|
|
||||||
if (strcmp(_processedNames[index], name) == 0)
|
|
||||||
return _value_array[index];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
throw std::exception();
|
constexpr static EnumType _from_string_nocase(const char *name)
|
||||||
}
|
|
||||||
|
|
||||||
// TODO Make constexpr.
|
|
||||||
static EnumType _from_string_nocase(const char *name)
|
|
||||||
{
|
{
|
||||||
_processNames();
|
return _value_array[_from_string_nocase_loop(name, true)];
|
||||||
|
|
||||||
for (size_t index = 0; index < _size; ++index) {
|
|
||||||
if (strcasecmp(_processedNames[index], name) == 0)
|
|
||||||
return _value_array[index];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
throw std::exception();
|
constexpr static bool _is_valid(_Integral value)
|
||||||
|
{
|
||||||
|
return _from_int_loop(value, false) != _ENUM_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr static bool _is_valid(const char *name)
|
||||||
|
{
|
||||||
|
return _from_string_loop(name, false) != _ENUM_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr static bool _is_valid_nocase(const char *name)
|
||||||
|
{
|
||||||
|
return _from_string_nocase_loop(name, false) != _ENUM_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
operator _Enumerated() { return _value; }
|
operator _Enumerated() { return _value; }
|
||||||
@ -595,50 +617,46 @@ class _Implementation : public _GeneratedArrays<EnumType> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// See comment by _isIterableIndex.
|
constexpr static size_t _from_int_loop(_Integral value,
|
||||||
#ifdef __clang__
|
bool throw_exception,
|
||||||
#pragma GCC diagnostic push
|
size_t index = 0)
|
||||||
#pragma GCC diagnostic ignored "-Wtautological-compare"
|
|
||||||
#endif // #ifdef __clang__
|
|
||||||
|
|
||||||
// TODO Do a real check here - look it up in the array.
|
|
||||||
template <typename IntegralType>
|
|
||||||
static bool _is_valid(IntegralType value)
|
|
||||||
{
|
{
|
||||||
static_assert(std::is_integral<IntegralType>::value,
|
return
|
||||||
"argument to EnumType::valid must have integral type");
|
index == _size ?
|
||||||
static_assert(std::is_signed<IntegralType>::value ==
|
(throw_exception ?
|
||||||
std::is_signed<_Integral>::value,
|
throw std::runtime_error(
|
||||||
"argument to EnumType::valid must be signed if and only "
|
"Enum::from_int: invalid integer value") :
|
||||||
"if underlying type of EnumType is signed");
|
_ENUM_NOT_FOUND) :
|
||||||
|
_value_array[index] == value ? index :
|
||||||
return true;
|
_from_int_loop(value, throw_exception, index + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __clang__
|
constexpr static size_t _from_string_loop(const char *name,
|
||||||
#pragma GCC diagnostic pop
|
bool throw_exception,
|
||||||
#endif // #ifdef __clang__
|
size_t index = 0)
|
||||||
|
|
||||||
static bool _is_valid(const char *name)
|
|
||||||
{
|
{
|
||||||
try {
|
return
|
||||||
_from_string(name);
|
index == _size ?
|
||||||
return true;
|
(throw_exception ?
|
||||||
}
|
throw std::runtime_error(
|
||||||
catch (const std::exception &e) {
|
"Enum::_from_string: invalid string argument") :
|
||||||
return false;
|
_ENUM_NOT_FOUND) :
|
||||||
}
|
_namesMatch(_name_array[index], name) ? index :
|
||||||
|
_from_string_loop(name, throw_exception, index + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _is_valid_nocase(const char *name)
|
constexpr static size_t _from_string_nocase_loop(const char *name,
|
||||||
|
bool throw_exception,
|
||||||
|
size_t index = 0)
|
||||||
{
|
{
|
||||||
try {
|
return
|
||||||
_from_string_nocase(name);
|
index == _size ?
|
||||||
return true;
|
(throw_exception ?
|
||||||
}
|
throw std::runtime_error(
|
||||||
catch (const std::exception &e) {
|
"Enum::_from_string_nocase: invalid string argument") :
|
||||||
return false;
|
_ENUM_NOT_FOUND) :
|
||||||
}
|
_namesMatchNocase(_name_array[index], name) ? index :
|
||||||
|
_from_string_nocase_loop(name, throw_exception, index + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Remove static casts wherever reasonable.
|
// TODO Remove static casts wherever reasonable.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user