Made basic interface constexpr and made default cast checked.

This commit is contained in:
Anton Bachin 2015-04-29 05:53:46 -04:00
parent 2127b89dd4
commit f55d2b56dc
2 changed files with 78 additions and 66 deletions

6
Enum.h
View File

@ -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__); \

View File

@ -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();
} }
// TODO Make constexpr. constexpr static EnumType _from_string_nocase(const char *name)
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) { constexpr static bool _is_valid(_Integral value)
if (strcasecmp(_processedNames[index], name) == 0) {
return _value_array[index]; return _from_int_loop(value, false) != _ENUM_NOT_FOUND;
} }
throw std::exception(); 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.
@ -703,8 +721,8 @@ class _Implementation : public _GeneratedArrays<EnumType> {
namespace _enum { \ namespace _enum { \
\ \
template <> \ template <> \
constexpr EnumType _Implementation<EnumType>::_first = \ constexpr EnumType _Implementation<EnumType>::_first = \
EnumType::_from_int(EnumType::_value_array[0]); \ EnumType::_from_int(EnumType::_value_array[0]); \
\ \
} }