Skip to content

Commit

Permalink
Merge pull request #229 from tcbrindle/pr/fix_228
Browse files Browse the repository at this point in the history
Fix issue #228
  • Loading branch information
tcbrindle authored Dec 31, 2024
2 parents f539c11 + a4b9bb6 commit 7b03114
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 24 deletions.
37 changes: 21 additions & 16 deletions include/flux/adaptor/set_adaptors.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ struct set_union_adaptor
public:
using value_type = std::common_type_t<value_t<Base1>, value_t<Base2>>;

inline static constexpr bool is_infinite = flux::infinite_sequence<Base1> ||
inline static constexpr bool is_infinite = flux::infinite_sequence<Base1> ||
flux::infinite_sequence<Base2>;

template <typename Self>
Expand All @@ -91,7 +91,7 @@ struct set_union_adaptor
requires maybe_const_iterable<Self>
static constexpr auto is_last(Self& self, cursor_type const& cur) -> bool
{
return flux::is_last(self.base1_, cur.base1_cursor) &&
return flux::is_last(self.base1_, cur.base1_cursor) &&
flux::is_last(self.base2_, cur.base2_cursor);
}

Expand All @@ -111,7 +111,7 @@ struct set_union_adaptor
template <typename Self>
requires maybe_const_iterable<Self>
static constexpr auto read_at(Self& self, cursor_type const& cur)
-> std::common_reference_t<decltype(flux::read_at(self.base1_, cur.base1_cursor)),
-> std::common_reference_t<decltype(flux::read_at(self.base1_, cur.base1_cursor)),
decltype(flux::read_at(self.base2_, cur.base2_cursor))>
{
if (cur.active_ == cursor_type::first) {
Expand All @@ -122,7 +122,7 @@ struct set_union_adaptor
}

template <typename Self>
requires maybe_const_iterable<Self> &&
requires maybe_const_iterable<Self> &&
bounded_sequence<Base1> && bounded_sequence<Base2>
static constexpr auto last(Self& self) -> cursor_type
{
Expand All @@ -132,7 +132,7 @@ struct set_union_adaptor
template <typename Self>
requires maybe_const_iterable<Self>
static constexpr auto move_at(Self& self, cursor_type const& cur)
-> std::common_reference_t<decltype(flux::move_at(self.base1_, cur.base1_cursor)),
-> std::common_reference_t<decltype(flux::move_at(self.base1_, cur.base1_cursor)),
decltype(flux::move_at(self.base2_, cur.base2_cursor))>
{
if (cur.active_ == cursor_type::first) {
Expand All @@ -141,7 +141,7 @@ struct set_union_adaptor
return flux::move_at(self.base2_, cur.base2_cursor);
}
}

};
};

Expand Down Expand Up @@ -244,7 +244,7 @@ struct set_difference_adaptor
{
return flux::move_at(self.base1_, cur.base1_cursor);
}

};
};

Expand Down Expand Up @@ -272,10 +272,13 @@ struct set_symmetric_difference_adaptor
cursor_t<Base2> base2_cursor;
enum : char {first, second, first_done, second_done} state_ = first;

friend auto operator==(cursor_type const&, cursor_type const&) -> bool
friend constexpr auto operator==(cursor_type const& lhs, cursor_type const& rhs) -> bool
requires std::equality_comparable<cursor_t<Base1>> &&
std::equality_comparable<cursor_t<Base2>>
= default;
{
return lhs.base1_cursor == rhs.base1_cursor &&
lhs.base2_cursor == rhs.base2_cursor;
}
};

template <typename Self>
Expand Down Expand Up @@ -311,7 +314,7 @@ struct set_symmetric_difference_adaptor
public:
using value_type = std::common_type_t<value_t<Base1>, value_t<Base2>>;

inline static constexpr bool is_infinite = flux::infinite_sequence<Base1> ||
inline static constexpr bool is_infinite = flux::infinite_sequence<Base1> ||
flux::infinite_sequence<Base2>;

template <typename Self>
Expand All @@ -328,7 +331,7 @@ struct set_symmetric_difference_adaptor
requires maybe_const_iterable<Self>
static constexpr auto is_last(Self& self, cursor_type const& cur) -> bool
{
return flux::is_last(self.base1_, cur.base1_cursor) &&
return flux::is_last(self.base1_, cur.base1_cursor) &&
flux::is_last(self.base2_, cur.base2_cursor);
}

Expand Down Expand Up @@ -370,7 +373,9 @@ struct set_symmetric_difference_adaptor
}

template <typename Self>
requires maybe_const_iterable<Self> && bounded_sequence<Base1>
requires maybe_const_iterable<Self> &&
bounded_sequence<Base1> &&
bounded_sequence<Base2>
static constexpr auto last(Self& self) -> cursor_type
{
return cursor_type{flux::last(self.base1_), flux::last(self.base2_)};
Expand Down Expand Up @@ -428,7 +433,7 @@ struct set_intersection_adaptor

template <typename Self>
static constexpr void update(Self& self, cursor_type& cur) {
while(not flux::is_last(self.base1_, cur.base1_cursor) &&
while(not flux::is_last(self.base1_, cur.base1_cursor) &&
not flux::is_last(self.base2_, cur.base2_cursor))
{
auto r = std::invoke(self.cmp_, flux::read_at(self.base1_, cur.base1_cursor),
Expand Down Expand Up @@ -463,7 +468,7 @@ struct set_intersection_adaptor
requires maybe_const_iterable<Self>
static constexpr auto is_last(Self& self, cursor_type const& cur) -> bool
{
return flux::is_last(self.base1_, cur.base1_cursor) ||
return flux::is_last(self.base1_, cur.base1_cursor) ||
flux::is_last(self.base2_, cur.base2_cursor);
}

Expand Down Expand Up @@ -491,7 +496,7 @@ struct set_intersection_adaptor
{
return flux::move_at(self.base1_, cur.base1_cursor);
}

};
};

Expand All @@ -503,7 +508,7 @@ concept set_op_compatible =

struct set_union_fn {
template <adaptable_sequence Seq1, adaptable_sequence Seq2, typename Cmp = std::compare_three_way>
requires set_op_compatible<Seq1, Seq2> &&
requires set_op_compatible<Seq1, Seq2> &&
weak_ordering_for<Cmp, Seq1> &&
weak_ordering_for<Cmp, Seq2>
[[nodiscard]]
Expand Down
44 changes: 36 additions & 8 deletions test/test_set_adaptors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include <array>
#include <utility>
#include <vector>

#include "test_utils.hpp"

Expand Down Expand Up @@ -110,8 +111,9 @@ constexpr bool test_set_union()
std::array<std::pair<int, char>, 3> arr1{{{0, 'a'}, {2, 'b'}, {4, 'c'}}};
std::array<std::pair<int, char>, 3> arr2{{{1, 'x'}, {3, 'y'}, {5, 'z'}}};

auto union_seq = flux::set_union(flux::ref(arr1), flux::ref(arr2),
flux::proj(flux::cmp::compare, [] (auto v) { return v.first; }));
auto union_seq
= flux::set_union(flux::ref(arr1), flux::ref(arr2),
flux::proj(flux::cmp::compare, [](auto v) { return v.first; }));

using T = decltype(union_seq);
static_assert(flux::sequence<T>);
Expand Down Expand Up @@ -267,8 +269,9 @@ constexpr bool test_set_difference()
std::array<std::pair<int, char>, 4> arr1{{{0, 'a'}, {1, 'b'}, {2, 'c'}, {3, 'd'}}};
std::array<std::pair<int, char>, 3> arr2{{{1, 'x'}, {2, 'y'}, {5, 'z'}}};

auto diff_seq = flux::set_difference(flux::ref(arr1), flux::ref(arr2),
flux::proj(flux::cmp::compare, [] (auto v) { return v.first; }));
auto diff_seq
= flux::set_difference(flux::ref(arr1), flux::ref(arr2),
flux::proj(flux::cmp::compare, [](auto v) { return v.first; }));

using T = decltype(diff_seq);
static_assert(flux::sequence<T>);
Expand Down Expand Up @@ -412,8 +415,9 @@ constexpr bool test_set_symmetric_difference()
std::array<std::pair<int, char>, 4> arr1{{{0, 'a'}, {1, 'b'}, {2, 'c'}, {3, 'd'}}};
std::array<std::pair<int, char>, 3> arr2{{{1, 'x'}, {2, 'y'}, {5, 'z'}}};

auto diff_seq = flux::set_symmetric_difference(flux::ref(arr1), flux::ref(arr2),
flux::proj(flux::cmp::compare, [] (auto v) { return v.first; }));
auto diff_seq = flux::set_symmetric_difference(
flux::ref(arr1), flux::ref(arr2),
flux::proj(flux::cmp::compare, [](auto v) { return v.first; }));

using T = decltype(diff_seq);
static_assert(flux::sequence<T>);
Expand Down Expand Up @@ -558,8 +562,9 @@ constexpr bool test_set_intersection()
std::array<std::pair<int, char>, 4> arr1{{{0, 'a'}, {1, 'b'}, {2, 'c'}, {3, 'd'}}};
std::array<std::pair<int, char>, 3> arr2{{{1, 'x'}, {2, 'y'}, {5, 'z'}}};

auto inter_seq = flux::set_intersection(flux::ref(arr1), flux::ref(arr2),
flux::proj(flux::cmp::compare, [] (auto v) { return v.first; }));
auto inter_seq = flux::set_intersection(
flux::ref(arr1), flux::ref(arr2),
flux::proj(flux::cmp::compare, [](auto v) { return v.first; }));

using T = decltype(inter_seq);
static_assert(flux::sequence<T>);
Expand Down Expand Up @@ -607,6 +612,27 @@ static_assert(test_set_difference());
static_assert(test_set_symmetric_difference());
static_assert(test_set_intersection());

// https://github.com/tcbrindle/flux/issues/228
constexpr bool issue_228()
{
std::array arr1 {0, 1, 2, 3, 4, 5};
std::array arr2 {1, 3, 5, 6, 7};
auto merged = flux::set_symmetric_difference(flux::ref(arr1), flux::ref(arr2));

STATIC_CHECK(flux::equal(merged, std::array {0, 2, 4, 6, 7}));

std::vector<int> out;

for (auto i : merged) {
// crashes here
out.push_back(i);
}

STATIC_CHECK(check_equal(out, merged));

return true;
}
static_assert(issue_228());
}

TEST_CASE("set_union")
Expand All @@ -625,6 +651,8 @@ TEST_CASE("set_symmetric_difference")
{
bool result = test_set_symmetric_difference();
REQUIRE(result);
result = issue_228();
REQUIRE(result);
}

TEST_CASE("set_intersection")
Expand Down

0 comments on commit 7b03114

Please sign in to comment.