Replaced _names() and _values() with constexpr iterables.

This commit is contained in:
Anton Bachin 2015-05-02 22:52:24 -04:00
parent f55d2b56dc
commit 2992a7f45d

View File

@ -70,9 +70,7 @@ namespace _enum {
// Forward declaration of _Internal, for use in a friend declation in _Iterable. // Forward declaration of _Internal, for use in a friend declation in _Iterable.
template <typename EnumType> class _Implementation; template <typename EnumType> class _Implementation;
// TODO Simplify - names iteration will need a custom iterator if processing // TODO Make these standard-compliant.
// strings lazily, while values can be done by simply iterating over the values
// array directly.
/// Template for iterable objects over enum names and values. /// Template for iterable objects over enum names and values.
/// ///
/// The iterables are intended for use with C++11 `for-each` syntax. They are /// The iterables are intended for use with C++11 `for-each` syntax. They are
@ -114,90 +112,100 @@ template <typename EnumType> class _Implementation;
/// considered valid if they are not equal to the bad value, are not below the /// considered valid if they are not equal to the bad value, are not below the
/// minimum value, and are not above the maximum value. Names are valid if they /// minimum value, and are not above the maximum value. Names are valid if they
/// are the name of a valid value. /// are the name of a valid value.
template <typename Element, typename EnumType, typename ArrayType>
class _Iterable { template <typename EnumType, typename Iterator>
class _Iterable;
template <typename EnumType>
class _ValueIterator {
public: public:
/// Iterators for iterating over enum names or values. constexpr EnumType operator *() const
class iterator {
public:
/// Returns the current name or value.
Element operator *() const { return (Element)_arrayPointer[_index]; }
/// Advances the iterator to the next valid name or value. If there is
/// no such value, the iterator becomes equal to the result of
/// `_Iterable::end()`.
/// @return A reference to itself.
iterator& operator ++()
{
if (_index < EnumType::_size)
++_index;
return *this;
}
/// Compares two iterators for equality.
/// @param other Another iterator over the same array.
bool operator ==(const iterator &other) const
{
return (other._arrayPointer == _arrayPointer) &&
(other._index == _index);
}
/// Compares two iterators for equality - negated comparison.
/// @param other Another iterator over the same array.
bool operator !=(const iterator &other) const
{ return !(*this == other); }
public:
/// An iterator can be declared without initialization - in this case,
/// its state is undefined.
iterator() = default;
private:
/// Constructs an iterator over the given array, with the given starting
/// index. This method is used only be the enclosing `_Iterable` class.
/// @param arrayPointer Array that will be iterated over.
/// @param index Initial index into the array. This must be the index of
/// a valid value.
iterator(ArrayType arrayPointer, size_t index) :
_arrayPointer(arrayPointer), _index(index) { }
/// Reference to the array being iterated.
ArrayType _arrayPointer;
/// Current index into the array. This is always either the index of a
/// valid value or else it is equal to the size of the array.
size_t _index;
/// Permit `_Iterable` to create iterators.
friend class _Iterable;
};
/// Returns an iterator to the beginning of the name or value array.
iterator begin() const
{ {
return iterator(_arrayPointer, 0); return EnumType::_value_array[_index];
} }
/// Returns an iterator to the end of the name or value array. // TODO Can this be constexpr if the iterator is allowed to be immutable?
iterator end() const _ValueIterator& operator ++()
{ {
return iterator(_arrayPointer, EnumType::_size); if (_index < EnumType::_size)
++_index;
return *this;
} }
/// Returns the number of valid elements (names or values) in the iterable - constexpr bool operator ==(const _ValueIterator &other) const
/// the number of times an iterator starting at `begin()` can be {
/// dereferenced and then advanced before reaching `end()`. return other._index == _index;
size_t size() const { return EnumType::size(); } }
constexpr bool operator !=(const _ValueIterator &other) const
{
return !(*this == other);
}
private: private:
/// Creates an `_Iterable` object over an array. constexpr _ValueIterator(size_t index) : _index(index) { }
_Iterable(ArrayType arrayPointer) : _arrayPointer(arrayPointer) { }
/// The array over which iteration will be performed. size_t _index;
ArrayType _arrayPointer;
/// Permit the enum class itself to create `_Iterable` objects. friend _Iterable<EnumType, _ValueIterator<EnumType>>;
friend class _Implementation<EnumType>; };
template <typename EnumType>
class _NameIterator {
public:
const char* operator *() const
{
return EnumType::_getProcessedName(_index);
}
_NameIterator& operator ++()
{
if (_index < EnumType::_size)
++_index;
return *this;
}
constexpr bool operator ==(const _NameIterator &other) const
{
return other._index == _index;
}
constexpr bool operator !=(const _NameIterator &other) const
{
return !(*this == other);
}
private:
constexpr _NameIterator(size_t index) : _index(index) { }
size_t _index;
friend _Iterable<EnumType, _NameIterator<EnumType>>;
};
template <typename EnumType, typename Iterator>
class _Iterable {
public:
using iterator = Iterator;
constexpr iterator begin() const
{
return iterator(0);
}
constexpr iterator end() const
{
return iterator(EnumType::_size);
}
constexpr size_t size() const { return EnumType::size(); }
private:
constexpr _Iterable() { };
friend _Implementation<EnumType>;
}; };
@ -414,15 +422,8 @@ constexpr size_t _size(const UnderlyingType *values, size_t valueCount,
} // namespace _enum } // namespace _enum
// TODO Document reliance on the order of strings and constants being the same.
// TODO Document naming convention: raw, blank, processed.
// TODO Note that the static_assert for _rawSize > 0 never really gets a chance // TODO Note that the static_assert for _rawSize > 0 never really gets a chance
// to fail in practice, because the preprocessor macros break before that. // to fail in practice, because the preprocessor macros break before that.
// TODO Argue why there is always a first regular and a last regular.
// TODO Document clang WAR for min and max.
// TODO Default should be the first index that is not the invalid index.
// TODO static asserts about the underlying type being an integral type. Allow
// only the types supported by C++11 enum class.
@ -598,24 +599,22 @@ class _Implementation : public _GeneratedArrays<EnumType> {
_processedNames = _enum::_processNames(_name_array, _size); _processedNames = _enum::_processNames(_name_array, _size);
} }
using _ValueIterable = static const char* _getProcessedName(size_t index)
_Iterable<const EnumType, EnumType, const _Enumerated * const>;
using _NameIterable =
_Iterable<const char*, EnumType, const char * const*>;
public:
static _ValueIterable _values()
{
return _ValueIterable(_value_array);
}
static _NameIterable _names()
{ {
_processNames(); _processNames();
return _processedNames[index];
return _NameIterable(_processedNames);
} }
using _ValueIterable = _Iterable<EnumType, _ValueIterator<EnumType>>;
using _NameIterable = _Iterable<EnumType, _NameIterator<EnumType>>;
friend _ValueIterator<EnumType>;
friend _NameIterator<EnumType>;
public:
static const _ValueIterable _values;
static const _NameIterable _names;
protected: protected:
constexpr static size_t _from_int_loop(_Integral value, constexpr static size_t _from_int_loop(_Integral value,
bool throw_exception, bool throw_exception,
@ -717,10 +716,17 @@ class _Implementation : public _GeneratedArrays<EnumType> {
template <typename T> int operator ||(T other) const = delete; template <typename T> int operator ||(T other) const = delete;
}; };
// TODO Investigate what happens when this is mixed with multiple compilation.
#define _ENUM_STATIC_DEFINITIONS(EnumType) \ #define _ENUM_STATIC_DEFINITIONS(EnumType) \
namespace _enum { \ namespace _enum { \
\ \
template <> \ template <> \
constexpr EnumType::_ValueIterable _Implementation<EnumType>::_values{}; \
\
template <> \
constexpr EnumType::_NameIterable _Implementation<EnumType>::_names{}; \
\
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]); \
\ \