Skip to content

Commit

Permalink
view::generate always std::input_range
Browse files Browse the repository at this point in the history
  • Loading branch information
OleErikPeistorpet committed Jun 16, 2024
1 parent 31abbb1 commit c6979f3
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 49 deletions.
23 changes: 22 additions & 1 deletion auxi/detail_assignable.h → auxi/detail_iter_with_func.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)


#include "core_util.h"
#include "../util.h" // for TightPair


namespace oel::_detail
Expand Down Expand Up @@ -60,4 +60,25 @@ namespace oel::_detail
public:
using Type = T;
};


template< typename T, typename Func, bool /*IsConstCallable*/ >
struct IterWithFuncBase
{
using FnRef = const Func &;

static constexpr auto canCallConst = true;

TightPair< T, typename AssignableWrap<Func>::Type > m;
};

template< typename T, typename Func >
struct IterWithFuncBase<T, Func, false>
{
using FnRef = Func &;

static constexpr auto canCallConst = false;

TightPair< T, typename AssignableWrap<Func>::Type > mutable m;
};
}
21 changes: 15 additions & 6 deletions unit_test/view_gtest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,10 +144,9 @@ using StdArrInt2 = std::array<int, 2>;
constexpr auto multBy2(StdArrInt2 a)
{
StdArrInt2 res{};
struct
{ constexpr auto operator()(int i) const { return 2 * i; }
} mult2{};
auto mult2 = [j = 2](int i) { return i * j; };
auto v = view::transform(a, mult2);

size_t i{};
for (auto val : v)
res[i++] = val;
Expand Down Expand Up @@ -274,6 +273,13 @@ struct Ints

TEST(viewTest, viewGenerate)
{
{
auto v = view::generate([] { return 7; }, 1);
for (auto i : v)
EXPECT_EQ(7, i);

static_assert(sizeof v.begin() <= sizeof(ptrdiff_t));
}
auto d = view::generate(Ints{1}, 2) | oel::to_dynarray();

ASSERT_EQ(2U, d.size());
Expand All @@ -282,6 +288,12 @@ TEST(viewTest, viewGenerate)

d.assign(oel::view::generate(Ints{}, 0));
EXPECT_TRUE(d.empty());

#if OEL_STD_RANGES
using G = decltype( view::generate(Ints{}, 2) );
static_assert(std::ranges::input_range<G>);
static_assert(std::ranges::sized_range<G>);
#endif
}

TEST(viewTest, viewMoveEndDifferentType)
Expand All @@ -305,9 +317,6 @@ TEST(viewTest, viewMoveMutableEmptyAndSize)
EXPECT_EQ(1U, v.size());
}

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

TEST(viewTest, chainWithStd)
{
auto f = [](int i) { return -i; };
Expand Down
49 changes: 36 additions & 13 deletions view/generate.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,46 +6,69 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)


#include "counted.h"
#include "../auxi/detail_assignable.h"
#include "subrange.h"
#include "../auxi/detail_iter_with_func.h"

/** @file
*/

namespace oel
{

struct _defaultSentinel {};


template< typename Generator >
class generate_iterator
class _generateIterator
: private _detail::IterWithFuncBase< ptrdiff_t, Generator, std::is_invocable_v<const Generator &> >
{
typename _detail::AssignableWrap<Generator>::Type mutable _g;
using _base = typename _generateIterator::IterWithFuncBase;

using _base::m;

public:
using iterator_category = std::input_iterator_tag;
using reference = decltype( std::declval<Generator &>()() );
using difference_type = ptrdiff_t;
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 generate_iterator(Generator g) : _g{std::move(g)} {}
constexpr _generateIterator(Generator g, difference_type count) : _base{{count, std::move(g)}} {}

constexpr reference operator*() const
{
return static_cast<Generator &>(_g)();
typename _base::FnRef g = m.second();
return g();
}

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

constexpr void operator++(int) & OEL_ALWAYS_INLINE { --m.first; }

friend constexpr difference_type operator -
(_defaultSentinel, const _generateIterator & right) { return right.m.first; }
friend constexpr difference_type operator -
(const _generateIterator & left, _defaultSentinel) { return -left.m.first; }

friend constexpr bool operator==(const _generateIterator & left, _defaultSentinel) { return 0 == left.m.first; }

friend constexpr bool operator==(_defaultSentinel left, const _generateIterator & right) { return right == left; }

friend constexpr bool operator!=(const _generateIterator & left, _defaultSentinel) { return 0 != left.m.first; }

friend constexpr bool operator!=(_defaultSentinel, const _generateIterator & right) { return 0 != right.m.first; }
};


namespace view
{
//! Returns a view that generates `count` elements by calling the given generator function
/**
* 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(generate_iterator{std::move(generator)}, count); };
* Almost same as `generate_n` in the Range-v3 library. */
inline constexpr auto generate = [](auto generator, ptrdiff_t count)
{
return subrange(_generateIterator{std::move(generator), count}, _defaultSentinel{});
};
}

} // oel
35 changes: 6 additions & 29 deletions view/transform_iterator.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,39 +6,14 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)


#include "../util.h" // for TightPair
#include "../auxi/detail_assignable.h"
#include "../auxi/detail_iter_with_func.h"
#include "../auxi/range_traits.h"

/** @file
*/

namespace oel
{
namespace _detail
{
template< typename Func, typename Iter,
bool = std::is_invocable_v< const Func &, decltype(*std::declval<Iter const>()) >
>
struct TransformIterBase
{
using FnRef = const Func &;

static constexpr auto canCallConst = true;

TightPair< Iter, typename AssignableWrap<Func>::Type > m;
};

template< typename Func, typename Iter >
struct TransformIterBase<Func, Iter, false>
{
using FnRef = Func &;

static constexpr auto canCallConst = false;

TightPair< Iter, typename AssignableWrap<Func>::Type > mutable m;
};
}


/** @brief Similar to boost::transform_iterator
*
Expand All @@ -49,9 +24,11 @@ namespace _detail
* - Function objects (including lambda) can have non-const `operator()`, then merely std::input_iterator is modeled */
template< typename UnaryFunc, typename Iterator >
class transform_iterator
: private _detail::TransformIterBase<UnaryFunc, Iterator>
: private _detail::IterWithFuncBase< Iterator, UnaryFunc,
std::is_invocable_v< const UnaryFunc &, decltype(*std::declval<Iterator const>()) >
>
{
using _super = typename transform_iterator::TransformIterBase;
using _super = typename transform_iterator::IterWithFuncBase;

using _super::m;

Expand Down

0 comments on commit c6979f3

Please sign in to comment.