Skip to content

Commit

Permalink
Fixed transform_iterator compile error corner case
Browse files Browse the repository at this point in the history
Unit tests updated.
When compiling with MSVC 2019, more constraints needed for transform_iterator equality operators.
  • Loading branch information
OleErikPeistorpet committed Sep 28, 2023
1 parent 97e9a28 commit a22128d
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 13 deletions.
2 changes: 2 additions & 0 deletions unit_test/dynarray_other_gtest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ namespace
#if __cpp_lib_concepts >= 201907
static_assert(std::contiguous_iterator<Iter>);
static_assert(std::contiguous_iterator<ConstIter>);
static_assert(std::sized_sentinel_for<ConstIter, Iter>);
static_assert(std::sized_sentinel_for<Iter, ConstIter>);
#endif

static_assert(std::is_same<std::iterator_traits<ConstIter>::value_type, float>(), "?");
Expand Down
20 changes: 17 additions & 3 deletions unit_test/view_gtest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,18 +70,21 @@ TEST(viewTest, viewTransformBasics)
{
using Elem = double;

struct MoveOnly
struct MoveOnlyF
{ std::unique_ptr<double> p;
auto operator()(Elem &) const { return 0; }
};
Elem r[1];
auto v = view::transform(r, [](Elem &) { return 0; });
auto v = r | view::transform([](Elem &) { return 0; });
auto v2 = view::transform(r, MoveOnlyF{});
auto itMoveOnly = v2.begin();

using IEmptyLambda = decltype(v.begin());
using IMoveOnly = oel::transform_iterator<MoveOnly, Elem *>;
using IMoveOnly = decltype(itMoveOnly);

static_assert(std::is_same< IEmptyLambda::iterator_category, std::bidirectional_iterator_tag >(), "?");
static_assert(std::is_same< IMoveOnly::iterator_category, std::input_iterator_tag >(), "?");
static_assert(std::is_same< decltype(itMoveOnly++), void >(), "?");
static_assert(sizeof(IEmptyLambda) == sizeof(Elem *), "Not critical, this assert can be removed");
#if OEL_STD_RANGES
static_assert(std::ranges::bidirectional_range<decltype(v)>);
Expand Down Expand Up @@ -244,4 +247,15 @@ TEST(viewTest, viewMoveMutableEmptyAndSize)
EXPECT_FALSE(v.empty());
EXPECT_EQ(1U, v.size());
}

TEST(viewTest, chainWithStd)
{
auto f = [](int i) { return -i; };
int src[] {0, 1};

void( src | view::move() | std::views::drop_while([](int i) { return i <= 0; }) );
void( src | std::views::reverse | view::transform(f) | std::views::take(1) );
void( src | view::transform(f) | std::views::drop(1) | view::move() );
}

#endif
29 changes: 19 additions & 10 deletions view/transform_iterator.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,16 +99,25 @@ class transform_iterator
OEL_REQUIRES(std::sized_sentinel_for<S, Iterator>)
friend constexpr difference_type operator -(S left, const transform_iterator & right) { return left - right._m.first; }

constexpr bool operator==(const transform_iterator & right) const { return _m.first == right._m.first; }
constexpr bool operator!=(const transform_iterator & right) const { return _m.first != right._m.first; }
template< typename Sentinel >
friend constexpr bool operator==(const transform_iterator & left, Sentinel right) { return left._m.first == right; }
template< typename Sentinel >
friend constexpr bool operator==(Sentinel left, const transform_iterator & right) { return right._m.first == left; }
template< typename Sentinel >
friend constexpr bool operator!=(const transform_iterator & left, Sentinel right) { return left._m.first != right; }
template< typename Sentinel >
friend constexpr bool operator!=(Sentinel left, const transform_iterator & right) { return right._m.first != left; }
constexpr bool operator==(const transform_iterator & right) const { return _m.first == right._m.first; }

constexpr bool operator!=(const transform_iterator & right) const { return _m.first != right._m.first; }

template< typename S >
OEL_REQUIRES(std::sentinel_for<S, Iterator>)
friend constexpr bool operator==(const transform_iterator & left, S right) { return left._m.first == right; }

template< typename S >
OEL_REQUIRES(std::sentinel_for<S, Iterator>)
friend constexpr bool operator==(S left, const transform_iterator & right) { return right._m.first == left; }

template< typename S >
OEL_REQUIRES(std::sentinel_for<S, Iterator>)
friend constexpr bool operator!=(const transform_iterator & left, S right) { return left._m.first != right; }

template< typename S >
OEL_REQUIRES(std::sentinel_for<S, Iterator>)
friend constexpr bool operator!=(S left, const transform_iterator & right) { return right._m.first != left; }
};

template< typename F, typename I >
Expand Down

0 comments on commit a22128d

Please sign in to comment.