Skip to content

Commit

Permalink
Add enum_base::begin() and enum_base::end()
Browse files Browse the repository at this point in the history
  • Loading branch information
jasujm committed Dec 8, 2019
1 parent 3db9a76 commit de22492
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 19 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ Unreleased

Added
- Add :cpp:func:`enhanced_enum::enum_base::ssize()`
- Add :cpp:func:`enhanced_enum::enum_base::begin()` and
:cpp:func:`enhanced_enum::enum_base::end()`

Fixed
- Add include guards to the C++ headers
Expand Down
46 changes: 37 additions & 9 deletions cxx/include/enhanced_enum/enhanced_enum.hh
Original file line number Diff line number Diff line change
Expand Up @@ -72,17 +72,32 @@ struct enum_base {

/** \brief Get range over all enumerators
*
* \return A random accessible range containing all enumerators in
* the order they are declared
* \return A random access range containing all enumerators in the
* order they are declared in the enum
*/
static constexpr auto all() noexcept
static constexpr decltype(auto) all() noexcept
{
constexpr auto N = size();
auto ret = std::array<EnhancedEnum, N> {};
for (auto i = 0u; i < N; ++i) {
ret[i] = static_cast<LabelEnum>(i);
}
return ret;
return *(&_enums_array);
}

/** \brief Get iterator to the first enumerator
*
* \return A random access iterator to the beginning of the range
* containing all enumerators in the order they are declared in
* the enum
*/
static constexpr auto begin() noexcept
{
return _enums_array.begin();
}

/** \brief Get iterator one past the last enumerator
*
* \return Iterator to the end of the range pointed to by begin()
*/
static constexpr auto end() noexcept
{
return _enums_array.end();
}

/** \brief Get the enumerator associated with \p value
Expand Down Expand Up @@ -150,6 +165,19 @@ struct enum_base {
}

private:

static constexpr auto _init_enums_array() noexcept
{
constexpr auto N = size();
auto ret = std::array<EnhancedEnum, N> {};
for (auto i = 0u; i < N; ++i) {
ret[i] = static_cast<LabelEnum>(i);
}
return ret;
}

constexpr static auto _enums_array = _init_enums_array();

LabelEnum label;
};

Expand Down
25 changes: 19 additions & 6 deletions cxx/tests/test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ using testapp::StatusLabel;
using testapp::EnhancedStatus;
namespace Statuses = testapp::Statuses;

namespace {

constexpr auto ALL_STATUSES = std::array {
Statuses::INITIALIZING,
Statuses::WAITING_FOR_INPUT,
Statuses::BUSY,
};

// Explicitly bundling label enum, enhanced enum and value to be consumed in the
// tests. Also defining operator<< to make the test reports pretty.

Expand All @@ -24,6 +32,8 @@ std::ostream& operator<<(std::ostream& os, const EnumBundle& bundle)
return os << bundle.value;
}

}

// Compiling the test executable is already a test:

static_assert( std::is_trivial_v<EnhancedStatus> );
Expand Down Expand Up @@ -111,15 +121,18 @@ TEST_P(EnhancedEnumTest, testConstructFromValue)
TEST_F(EnhancedEnumTest, testAll)
{
const auto all_enumerators = EnhancedStatus::all();
const auto expected = {
Statuses::INITIALIZING,
Statuses::WAITING_FOR_INPUT,
Statuses::BUSY,
};
EXPECT_TRUE(
std::equal(
all_enumerators.begin(), all_enumerators.end(),
expected.begin(), expected.end()));
ALL_STATUSES.begin(), ALL_STATUSES.end()));
}

TEST_F(EnhancedEnumTest, testBeginEnd)
{
EXPECT_TRUE(
std::equal(
EnhancedStatus::begin(), EnhancedStatus::end(),
ALL_STATUSES.begin(), ALL_STATUSES.end()));
}

INSTANTIATE_TEST_SUITE_P(
Expand Down
19 changes: 15 additions & 4 deletions docs/enhancedenumlib.rst
Original file line number Diff line number Diff line change
Expand Up @@ -241,8 +241,8 @@ deliberately explicit.
static_assert( Statuses::INITIALIZING.get() == StatusLabel::INITIALIZING )
static_assert( static_cast<StatusLabel>(Statuses::INITIALIZING) == StatusLabel::INITIALIZING );

Enumerators as range
....................
Enumerator ranges
.................

The number of enumerators in an enhanced enum type can be queries by
using the :cpp:func:`size()` and :cpp:func:`ssize()`, for unsigned and
Expand All @@ -260,10 +260,21 @@ constructed with the static :cpp:func:`all()` method:
The returned range can be used in compile time and has all the
enumerators in the same order as they are declared in the type.

For interfaces consuming iterator pairs, using :cpp:func:`begin()` and
:cpp:func:`end()` may be more convenient:

.. code-block:: c++

std::for_each(
EnhancedStatus::begin(), EnhancedStatus::end(),
[](const auto status) { /* use status */ });
In the current implementation the range is just an array, but this is
an implementation detail that may change in the future. The user
should not assume an underlying type returned by the :cpp:func:`all()`
method, except that it supports random access.
should not assume an underlying type returned by the
:cpp:func:`all()`, :cpp:func:`begin()` and :cpp:func:`end()`
functions, except that the ranges and iterators supports random
access.

Library reference
-----------------
Expand Down

0 comments on commit de22492

Please sign in to comment.