Skip to content

Commit

Permalink
Hack: generate_iterator with mutable member
Browse files Browse the repository at this point in the history
for std::input_iterator concept.
Also constexpr unit test
  • Loading branch information
OleErikPeistorpet committed Jun 16, 2024
1 parent f3520c0 commit b2b6ba2
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 9 deletions.
23 changes: 22 additions & 1 deletion unit_test/view_gtest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,27 @@ TEST(viewTest, viewTransformAsOutput)
EXPECT_EQ(-2, test[1].second);
}

constexpr StdArrInt2 generatedArray()
{
StdArrInt2 res{};
int i{1};
auto v = view::generate([&i] { return i++; }, 2);
auto it = v.begin();
for (auto & val : res)
{
val = *it;
it++;
}
return res;
}

constexpr void testViewGenerateConstexpr()
{
constexpr auto res = generatedArray();
static_assert(res[0] == 1);
static_assert(res[1] == 2);
}

struct Ints
{
int i;
Expand Down Expand Up @@ -285,7 +306,7 @@ TEST(viewTest, viewMoveMutableEmptyAndSize)
}

using IntGenIter = oel::iterator_t<decltype( view::generate(Ints{}, 0) )>;
static_assert(std::input_or_output_iterator<IntGenIter>);
static_assert(std::input_iterator<IntGenIter>);

TEST(viewTest, chainWithStd)
{
Expand Down
36 changes: 28 additions & 8 deletions view/generate.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,27 +14,47 @@

namespace oel
{
namespace _detail
{
template< typename G, bool = std::is_invocable_v<const G &> >
struct GenerateIterBase
{
using FnRef = const G &;

typename _detail::AssignableWrap<G>::Type g;
};

template< typename G >
struct GenerateIterBase<G, false>
{
using FnRef = G &;

typename _detail::AssignableWrap<G>::Type mutable g;
};
}


template< typename Generator >
class _generateIterator
class generate_iterator
: private _detail::GenerateIterBase<Generator>
{
typename _detail::AssignableWrap<Generator>::Type _g;
using _base = typename generate_iterator::GenerateIterBase;

public:
using iterator_category = std::input_iterator_tag;
using reference = decltype( std::declval<Generator &>()() );
using reference = decltype( std::declval<typename _base::FnRef>()() );
using pointer = void;
using value_type = std::remove_cv_t< std::remove_reference_t<reference> >;
using difference_type = ptrdiff_t;

constexpr explicit _generateIterator(Generator g) : _g{std::move(g)} {}
constexpr explicit generate_iterator(Generator g) : _base{std::move(g)} {}

constexpr reference operator*()
constexpr reference operator*() const
{
return static_cast<Generator &>(_g)();
typename _base::FnRef r = this->g; return r();
}

constexpr _generateIterator & operator++() OEL_ALWAYS_INLINE { return *this; }
constexpr generate_iterator & operator++() OEL_ALWAYS_INLINE { return *this; }
constexpr void operator++(int) & OEL_ALWAYS_INLINE {}
};

Expand All @@ -45,7 +65,7 @@ namespace view
/**
* Like `generate_n` in the Range-v3 library, but this is only for use within OE-Lib. */
inline constexpr auto generate =
[](auto generator, ptrdiff_t count) { return counted(_generateIterator{std::move(generator)}, count); };
[](auto generator, ptrdiff_t count) { return counted(generate_iterator{std::move(generator)}, count); };
}

} // oel

0 comments on commit b2b6ba2

Please sign in to comment.