Skip to content

Instantly share code, notes, and snippets.

@Redchards
Created April 20, 2016 20:51
Show Gist options
  • Select an option

  • Save Redchards/dc9c790274ff57051a6da38fc85e4f41 to your computer and use it in GitHub Desktop.

Select an option

Save Redchards/dc9c790274ff57051a6da38fc85e4f41 to your computer and use it in GitHub Desktop.
A retought and cleaned up version of the iteratable enum. Considered not that useful.
#ifndef ITERATABLE_ENUM_HXX
#define ITERATABLE_ENUM_HXX
#include <exception>
#include <type_traits>
#include <string>
#include <sstream>
#include <utility>
/* A simple set of functionnality aiming to emulate an interatable enum.
* However, I then found it not that useful, and somewhat error prone. Indeed, to work properly,
* the class must receive a linear enum (that said, all indices are following each others), and there's
* currently no real way to check that.
* I implemented a more useful functionality in the EnumUtils.hxx, the ITERATABLE_ENUM.
* This macro supports iteratable enum generation, and free serialization.
* However, all macros macros macros ...
*/
class IndexOutOfRange
{
public:
IndexOutOfRange(const char* msg, size_t index) : msg_(msg), index_(index) {}
std::string what() const noexcept
{
std::ostringstream sstr(std::ios_base::ate);
sstr << msg_ << ". At index : " << index_;
return sstr.str();
}
private:
const char* msg_;
size_t index_;
};
namespace detail
{
template<class T>
class HasEnumBeginEnd
{
private:
template<typename U>
static std::integral_constant<bool, (U::begin, U::end, true)> check(int);
template<typename U>
static std::false_type check(...);
public:
static constexpr bool value = decltype(check<T>(0))::value;
};
template<class Enum>
struct IsStronglyTypedEnum
{
static constexpr bool value = (std::is_enum<Enum>::value && !std::is_convertible<Enum, int>::value);
};
template<class Enum>
constexpr auto enumToUnderlying(Enum value) noexcept
{
static_assert(IsStronglyTypedEnum<Enum>::value,
"Can't access to the underlying type : the type is not a strongly typed enum !");
return static_cast<std::underlying_type_t<Enum>>(value);
}
}
template<class Enum>
auto operator*(Enum falsePointer) noexcept
-> std::enable_if_t<detail::IsStronglyTypedEnum<Enum>::value, Enum>
{
return falsePointer;
}
template<class Enum>
auto operator++(Enum& lhs, int) noexcept
-> std::enable_if_t<detail::IsStronglyTypedEnum<Enum>::value, Enum>
{
Enum tmp = lhs;
lhs = static_cast<Enum>(detail::enumToUnderlying(lhs) + 1);
return tmp;
}
template<class Enum>
auto operator++(Enum& rhs) noexcept
-> std::enable_if_t<detail::IsStronglyTypedEnum<Enum>::value, Enum>
{
return rhs = static_cast<Enum>(detail::enumToUnderlying(rhs) + 1);
}
template<class Enum>
auto operator--(Enum& lhs, int) noexcept
-> std::enable_if_t<detail::IsStronglyTypedEnum<Enum>::value, Enum>
{
Enum tmp = lhs;
lhs = static_cast<Enum>(detail::enumToUnderlying(lhs) - 1);
return tmp;
}
template<class Enum>
auto operator--(Enum& rhs) noexcept
-> std::enable_if_t<detail::IsStronglyTypedEnum<Enum>::value, Enum>
{
return rhs = static_cast<Enum>(detail::enumToUnderlying(rhs) - 1);
}
template<class Enum>
constexpr auto operator+(Enum lhs, size_t offset) noexcept
-> typename std::enable_if<detail::IsStronglyTypedEnum<Enum>::value, Enum>::type
{
return static_cast<Enum>(detail::enumToUnderlying(lhs) + offset);
}
template<class Enum>
constexpr auto operator-(Enum lhs, size_t offset) noexcept
-> typename std::enable_if<detail::IsStronglyTypedEnum<Enum>::value, Enum>::type
{
return static_cast<Enum>(detail::enumToUnderlying(lhs) - offset);
}
template<class Enum>
constexpr auto operator+(Enum lhs, Enum rhs) noexcept
-> std::enable_if_t<detail::IsStronglyTypedEnum<Enum>::value, Enum>
{
return static_cast<Enum>(detail::enumToUnderlying(lhs) + detail::enumToUnderlying(rhs));
}
template<class Enum>
constexpr auto operator-(Enum lhs, Enum rhs) noexcept
-> std::enable_if_t<detail::IsStronglyTypedEnum<Enum>::value, Enum>
{
return static_cast<Enum>(detail::enumToUnderlying(lhs) - detail::enumToUnderlying(rhs));
}
template<class Enum>
class IteratableEnum
{
static_assert(detail::IsStronglyTypedEnum<Enum>::value,
"This type only support strongly typed enum, whereas the passed parameted wasn't one.");
static_assert(detail::HasEnumBeginEnd<Enum>::value,
"Can't apply this type to an enum without 'begin' and 'end' field !");
static_assert(Enum::begin < Enum::end,
"Wrong value for begin and end in the enum : end >= begin !");
/*static_assert(IsLinearEnum<Enum>::value,
"The iterated enum should be linear.");*/
public:
using iterator = Enum;
public:
constexpr IteratableEnum() noexcept = default;
Enum constexpr operator*() const noexcept { return begin(); }
static constexpr typename std::underlying_type<Enum>::type toUnderlying(Enum param) noexcept
{
return detail::enumToUnderlying(param);
}
static constexpr Enum begin() noexcept { return Enum::begin; };
static constexpr Enum end() noexcept { return Enum::end; };
static Enum at(size_t index)
{
if (index > toUnderlying(Enum::end))
{
throw IndexOutOfRange("Index out of enumeration range", index);
}
else
{
return begin() + index;
}
}
size_t findPosition(Enum enumerator) const
{
size_t count = 0;
for (auto elem : *this)
{
if (elem == enumerator)
{
return count;
}
++count;
}
throw IndexOutOfRange("Element not in enumeration.\
Please do not typecast from integer when using this function !!!", count);
}
static constexpr size_t size() noexcept
{
/*size_t tmp = 0;
for (auto elem : *this)
{
++tmp;
}*/
return toUnderlying(end() - begin());
}
};
#endif // ITERATABLE_ENUM_HXX
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment