Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added indexable properties on enums #59

Merged
merged 14 commits into from
Sep 6, 2018
53 changes: 53 additions & 0 deletions enum.h
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,12 @@ BETTER_ENUMS_CONSTEXPR_ static T* _or_null(optional<T*> maybe)
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
Expand Down Expand Up @@ -615,6 +621,15 @@ class Enum { \
_from_integral_unchecked(_integral value); \
BETTER_ENUMS_CONSTEXPR_ static _optional \
_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; \
BETTER_ENUMS_IF_EXCEPTIONS( \
Expand Down Expand Up @@ -660,6 +675,8 @@ class Enum { \
\
BETTER_ENUMS_CONSTEXPR_ static _optional_index \
_from_value_loop(_integral value, std::size_t index = 0); \
BETTER_ENUMS_CONSTEXPR_ static _optional \
_from_index_loop(std::size_t index); \
BETTER_ENUMS_CONSTEXPR_ static _optional_index \
_from_string_loop(const char *name, std::size_t index = 0); \
BETTER_ENUMS_CONSTEXPR_ static _optional_index \
Expand Down Expand Up @@ -700,6 +717,15 @@ Enum::_from_value_loop(Enum::_integral value, std::size_t index) \
_from_value_loop(value, index + 1); \
} \
\
BETTER_ENUMS_CONSTEXPR_ inline Enum::_optional \
Enum::_from_index_loop(std::size_t index) \
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I recommend not calling this ..._loop, because it doesn't loop over the indexes, but just does a direct lookup. In fact, it looks like just the implementation of _from_index_nothrow, so I suggest moving it there.

{ \
return \
index >= _size() ? \
_optional() : \
_optional(BETTER_ENUMS_NS(Enum)::_value_array[index]); \
} \
\
BETTER_ENUMS_CONSTEXPR_ inline Enum::_optional_index \
Enum::_from_string_loop(const char *name, std::size_t index) \
{ \
Expand Down Expand Up @@ -727,6 +753,33 @@ BETTER_ENUMS_CONSTEXPR_ inline Enum::_integral Enum::_to_integral() const \
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 _from_index_loop(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 \
Enum::_from_integral_unchecked(_integral value) \
{ \
Expand Down
90 changes: 90 additions & 0 deletions test/cxxtest/general.h
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,96 @@ class EnumTests : public CxxTest::TestSuite {
+test::Namespaced::One);
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));
}
};


Expand Down