Added indexable properties on enums (#59)

- _to_index which return value 0... size-1
        (even if enums are note sequential)
 - _from_index used for other way around
 - _from_index_nothrow no throw version
 - _from_index_unchecked returns invalid enum
        in case arg>=size

Code and test cases added.
No documentation updates (my English is too poor for that)
This commit is contained in:
Piotr Kosek 2018-09-07 00:39:31 +02:00 committed by Anton Bachin
parent e5549fb18c
commit 97d38d8077
2 changed files with 135 additions and 0 deletions

45
enum.h
View File

@ -343,6 +343,12 @@ BETTER_ENUMS_CONSTEXPR_ static T* _or_null(optional<T*> maybe)
return maybe ? *maybe : BETTER_ENUMS_NULLPTR; return maybe ? *maybe : BETTER_ENUMS_NULLPTR;
} }
template <typename T>
BETTER_ENUMS_CONSTEXPR_ static T _or_zero(optional<T> maybe)
{
return maybe ? *maybe : T::_from_integral_unchecked(0);
}
// Functional sequencing. This is essentially a comma operator wrapped in a // Functional sequencing. This is essentially a comma operator wrapped in a
@ -615,6 +621,15 @@ class Enum { \
_from_integral_unchecked(_integral value); \ _from_integral_unchecked(_integral value); \
BETTER_ENUMS_CONSTEXPR_ static _optional \ BETTER_ENUMS_CONSTEXPR_ static _optional \
_from_integral_nothrow(_integral value); \ _from_integral_nothrow(_integral value); \
\
BETTER_ENUMS_CONSTEXPR_ std::size_t _to_index() const; \
BETTER_ENUMS_IF_EXCEPTIONS( \
BETTER_ENUMS_CONSTEXPR_ static Enum _from_index(std::size_t value); \
) \
BETTER_ENUMS_CONSTEXPR_ static Enum \
_from_index_unchecked(std::size_t value); \
BETTER_ENUMS_CONSTEXPR_ static _optional \
_from_index_nothrow(std::size_t value); \
\ \
ToStringConstexpr const char* _to_string() const; \ ToStringConstexpr const char* _to_string() const; \
BETTER_ENUMS_IF_EXCEPTIONS( \ BETTER_ENUMS_IF_EXCEPTIONS( \
@ -727,6 +742,36 @@ BETTER_ENUMS_CONSTEXPR_ inline Enum::_integral Enum::_to_integral() const \
return _integral(_value); \ return _integral(_value); \
} \ } \
\ \
BETTER_ENUMS_CONSTEXPR_ inline std::size_t Enum::_to_index() const \
{ \
return *_from_value_loop(_value); \
} \
\
BETTER_ENUMS_CONSTEXPR_ inline Enum \
Enum::_from_index_unchecked(std::size_t index) \
{ \
return \
::better_enums::_or_zero(_from_index_nothrow(index)); \
} \
\
BETTER_ENUMS_CONSTEXPR_ inline Enum::_optional \
Enum::_from_index_nothrow(std::size_t index) \
{ \
return \
index >= _size() ? \
_optional() : \
_optional(BETTER_ENUMS_NS(Enum)::_value_array[index]); \
} \
\
BETTER_ENUMS_IF_EXCEPTIONS( \
BETTER_ENUMS_CONSTEXPR_ inline Enum Enum::_from_index(std::size_t index) \
{ \
return \
::better_enums::_or_throw(_from_index_nothrow(index), \
#Enum "::_from_index: invalid argument"); \
} \
) \
\
BETTER_ENUMS_CONSTEXPR_ inline Enum \ BETTER_ENUMS_CONSTEXPR_ inline Enum \
Enum::_from_integral_unchecked(_integral value) \ Enum::_from_integral_unchecked(_integral value) \
{ \ { \

View File

@ -313,6 +313,96 @@ class EnumTests : public CxxTest::TestSuite {
+test::Namespaced::One); +test::Namespaced::One);
TS_ASSERT_EQUALS(strcmp(*test::Namespaced::_names().begin(), "One"), 0); TS_ASSERT_EQUALS(strcmp(*test::Namespaced::_names().begin(), "One"), 0);
} }
void test_to_index()
{
TS_ASSERT_EQUALS((+Channel::Red)._to_index(), 0);
TS_ASSERT_EQUALS((+Channel::Green)._to_index(), 1);
TS_ASSERT_EQUALS((+Channel::Blue)._to_index(), 2);
TS_ASSERT_EQUALS((+Depth::HighColor)._to_index(), 0);
TS_ASSERT_EQUALS((+Depth::TrueColor)._to_index(), 1);
TS_ASSERT_EQUALS((+Compression::None)._to_index(), 0);
TS_ASSERT_EQUALS((+Compression::Huffman)._to_index(), 1);
// TS_ASSERT_EQUALS((+Compression::Default)._to_index(), 2); // This won't pass as Compression::Huffman == Compression::Default
}
void test_from_index()
{
TS_ASSERT_EQUALS((+Channel::Red), Channel::_from_index(0));
TS_ASSERT_EQUALS((+Channel::Green), Channel::_from_index(1));
TS_ASSERT_EQUALS((+Channel::Blue), Channel::_from_index(2));
TS_ASSERT_THROWS(Channel::_from_index(42), std::runtime_error);
TS_ASSERT_EQUALS((+Depth::HighColor), Depth::_from_index(0));
TS_ASSERT_EQUALS((+Depth::TrueColor), Depth::_from_index(1));
TS_ASSERT_THROWS(Depth::_from_index(42), std::runtime_error);
TS_ASSERT_EQUALS((+Compression::None), Compression::_from_index(0));
TS_ASSERT_EQUALS((+Compression::Huffman), Compression::_from_index(1));
TS_ASSERT_EQUALS((+Compression::Default), Compression::_from_index(2));
TS_ASSERT_THROWS(Compression::_from_index(42), std::runtime_error);
}
void test_from_index_nothrow()
{
better_enums::optional<Channel> maybe_channel = Channel::_from_index_nothrow(0);
TS_ASSERT(maybe_channel);
TS_ASSERT_EQUALS(*maybe_channel, +Channel::Red);
maybe_channel = Channel::_from_index_nothrow(1);
TS_ASSERT(maybe_channel);
TS_ASSERT_EQUALS(*maybe_channel, +Channel::Green);
maybe_channel = Channel::_from_index_nothrow(2);
TS_ASSERT(maybe_channel);
TS_ASSERT_EQUALS(*maybe_channel, +Channel::Blue);
maybe_channel = Channel::_from_index_nothrow(45);
TS_ASSERT(!maybe_channel);
better_enums::optional<Depth> maybe_depth = Depth::_from_index_nothrow(0);
TS_ASSERT(maybe_depth);
TS_ASSERT_EQUALS(*maybe_depth, +Depth::HighColor);
maybe_depth = Depth::_from_index_nothrow(1);
TS_ASSERT(maybe_depth);
TS_ASSERT_EQUALS(*maybe_depth, +Depth::TrueColor);
maybe_depth = Depth::_from_index_nothrow(45);
TS_ASSERT(!maybe_depth);
better_enums::optional<Compression> maybe_compression = Compression::_from_index_nothrow(0);
TS_ASSERT(maybe_compression);
TS_ASSERT_EQUALS(*maybe_compression, +Compression::None);
maybe_compression = Compression::_from_index_nothrow(1);
TS_ASSERT(maybe_compression);
TS_ASSERT_EQUALS(*maybe_compression, +Compression::Huffman);
maybe_compression = Compression::_from_index_nothrow(2);
TS_ASSERT(maybe_compression);
TS_ASSERT_EQUALS(*maybe_compression, +Compression::Default);
maybe_compression = Compression::_from_index_nothrow(45);
TS_ASSERT(!maybe_compression);
}
void test_from_index_unchecked()
{
TS_ASSERT_EQUALS((+Channel::Red), Channel::_from_index_unchecked(0));
TS_ASSERT_EQUALS((+Channel::Green), Channel::_from_index_unchecked(1));
TS_ASSERT_EQUALS((+Channel::Blue), Channel::_from_index_unchecked(2));
TS_ASSERT_EQUALS((+Depth::HighColor), Depth::_from_index_unchecked(0));
TS_ASSERT_EQUALS((+Depth::TrueColor), Depth::_from_index_unchecked(1));
TS_ASSERT_EQUALS((+Compression::None), Compression::_from_index_unchecked(0));
TS_ASSERT_EQUALS((+Compression::Huffman), Compression::_from_index_unchecked(1));
TS_ASSERT_EQUALS((+Compression::Default), Compression::_from_index_unchecked(2));
}
}; };