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 14, 2024
1 parent 4463663 commit 58f117c
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 66 deletions.
31 changes: 26 additions & 5 deletions auxi/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 @@ -37,12 +37,12 @@ namespace oel::_detail
OEL_ALWAYS_INLINE constexpr operator T &() { return _val; }
};

using Empty_type_MSVC_unique_name = T;
using EmptyType_7KQw = T;

struct ImplEmpty : Empty_type_MSVC_unique_name
struct ImplEmpty : EmptyType_7KQw
{
constexpr ImplEmpty(Empty_type_MSVC_unique_name src) noexcept
: Empty_type_MSVC_unique_name(src) {}
constexpr ImplEmpty(EmptyType_7KQw src) noexcept
: EmptyType_7KQw(src) {}

ImplEmpty() = default;
ImplEmpty(const ImplEmpty &) = default;
Expand All @@ -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 @@ -253,6 +252,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 @@ -261,6 +267,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 @@ -284,9 +296,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
17 changes: 9 additions & 8 deletions util.h
Original file line number Diff line number Diff line change
Expand Up @@ -167,19 +167,20 @@ namespace _detail
OEL_ALWAYS_INLINE constexpr U & second() { return _sec; }
};

template< typename Type_unique_name_for_MSVC, typename Empty_type_MSVC_unique_name >
struct TightPair<Type_unique_name_for_MSVC, Empty_type_MSVC_unique_name, true>
: Empty_type_MSVC_unique_name
// MSVC needs unique names to guard against name collision due to inheritance
template< typename FirstType_7KQw, typename EmptyType_7KQw >
struct TightPair<FirstType_7KQw, EmptyType_7KQw, true>
: EmptyType_7KQw
{
Type_unique_name_for_MSVC first;
FirstType_7KQw first;

TightPair() = default;
constexpr TightPair(Type_unique_name_for_MSVC f, Empty_type_MSVC_unique_name s)
: Empty_type_MSVC_unique_name{s}, first{std::move(f)}
constexpr TightPair(FirstType_7KQw f, EmptyType_7KQw s)
: EmptyType_7KQw{s}, first{std::move(f)}
{}

OEL_ALWAYS_INLINE constexpr const Empty_type_MSVC_unique_name & second() const { return *this; }
OEL_ALWAYS_INLINE constexpr Empty_type_MSVC_unique_name & second() { return *this; }
OEL_ALWAYS_INLINE constexpr const EmptyType_7KQw & second() const { return *this; }
OEL_ALWAYS_INLINE constexpr EmptyType_7KQw & second() { return *this; }
};
}

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/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
45 changes: 11 additions & 34 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/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,18 +24,20 @@ 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 _base = typename transform_iterator::TransformIterBase;
using _super = typename transform_iterator::IterWithFuncBase;

using _base::m;
using _super::m;

static constexpr auto _isBidirectional = iter_is_bidirectional<Iterator>;

public:
using iterator_category =
std::conditional_t<
std::is_copy_constructible_v<UnaryFunc> and _base::canCallConst,
std::is_copy_constructible_v<UnaryFunc> and _super::canCallConst,
std::conditional_t<
_isBidirectional,
std::bidirectional_iterator_tag,
Expand All @@ -69,20 +46,20 @@ class transform_iterator
std::input_iterator_tag
>;
using difference_type = iter_difference_t<Iterator>;
using reference = decltype( std::declval<typename _base::FnRef>()(*m.first) );
using reference = decltype( std::declval<typename _super::FnRef>()(*m.first) );
using pointer = void;
using value_type = std::remove_cv_t< std::remove_reference_t<reference> >;

transform_iterator() = default;
constexpr transform_iterator(UnaryFunc f, Iterator it) : _base{{std::move(it), std::move(f)}} {}
constexpr transform_iterator(UnaryFunc f, Iterator it) : _super{{std::move(it), std::move(f)}} {}

constexpr Iterator base() && { return std::move(m.first); }
constexpr Iterator base() const && { return m.first; }
constexpr const Iterator & base() const & noexcept OEL_ALWAYS_INLINE { return m.first; }

constexpr reference operator*() const
{
typename _base::FnRef f = m.second();
typename _super::FnRef f = m.second();
return f(*m.first);
}

Expand Down

0 comments on commit 58f117c

Please sign in to comment.