Created
April 20, 2016 20:51
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #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