Skip to content

Commit 7b03114

Browse files
authored
Merge pull request #229 from tcbrindle/pr/fix_228
Fix issue #228
2 parents f539c11 + a4b9bb6 commit 7b03114

File tree

2 files changed

+57
-24
lines changed

2 files changed

+57
-24
lines changed

include/flux/adaptor/set_adaptors.hpp

+21-16
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ struct set_union_adaptor
7474
public:
7575
using value_type = std::common_type_t<value_t<Base1>, value_t<Base2>>;
7676

77-
inline static constexpr bool is_infinite = flux::infinite_sequence<Base1> ||
77+
inline static constexpr bool is_infinite = flux::infinite_sequence<Base1> ||
7878
flux::infinite_sequence<Base2>;
7979

8080
template <typename Self>
@@ -91,7 +91,7 @@ struct set_union_adaptor
9191
requires maybe_const_iterable<Self>
9292
static constexpr auto is_last(Self& self, cursor_type const& cur) -> bool
9393
{
94-
return flux::is_last(self.base1_, cur.base1_cursor) &&
94+
return flux::is_last(self.base1_, cur.base1_cursor) &&
9595
flux::is_last(self.base2_, cur.base2_cursor);
9696
}
9797

@@ -111,7 +111,7 @@ struct set_union_adaptor
111111
template <typename Self>
112112
requires maybe_const_iterable<Self>
113113
static constexpr auto read_at(Self& self, cursor_type const& cur)
114-
-> std::common_reference_t<decltype(flux::read_at(self.base1_, cur.base1_cursor)),
114+
-> std::common_reference_t<decltype(flux::read_at(self.base1_, cur.base1_cursor)),
115115
decltype(flux::read_at(self.base2_, cur.base2_cursor))>
116116
{
117117
if (cur.active_ == cursor_type::first) {
@@ -122,7 +122,7 @@ struct set_union_adaptor
122122
}
123123

124124
template <typename Self>
125-
requires maybe_const_iterable<Self> &&
125+
requires maybe_const_iterable<Self> &&
126126
bounded_sequence<Base1> && bounded_sequence<Base2>
127127
static constexpr auto last(Self& self) -> cursor_type
128128
{
@@ -132,7 +132,7 @@ struct set_union_adaptor
132132
template <typename Self>
133133
requires maybe_const_iterable<Self>
134134
static constexpr auto move_at(Self& self, cursor_type const& cur)
135-
-> std::common_reference_t<decltype(flux::move_at(self.base1_, cur.base1_cursor)),
135+
-> std::common_reference_t<decltype(flux::move_at(self.base1_, cur.base1_cursor)),
136136
decltype(flux::move_at(self.base2_, cur.base2_cursor))>
137137
{
138138
if (cur.active_ == cursor_type::first) {
@@ -141,7 +141,7 @@ struct set_union_adaptor
141141
return flux::move_at(self.base2_, cur.base2_cursor);
142142
}
143143
}
144-
144+
145145
};
146146
};
147147

@@ -244,7 +244,7 @@ struct set_difference_adaptor
244244
{
245245
return flux::move_at(self.base1_, cur.base1_cursor);
246246
}
247-
247+
248248
};
249249
};
250250

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

275-
friend auto operator==(cursor_type const&, cursor_type const&) -> bool
275+
friend constexpr auto operator==(cursor_type const& lhs, cursor_type const& rhs) -> bool
276276
requires std::equality_comparable<cursor_t<Base1>> &&
277277
std::equality_comparable<cursor_t<Base2>>
278-
= default;
278+
{
279+
return lhs.base1_cursor == rhs.base1_cursor &&
280+
lhs.base2_cursor == rhs.base2_cursor;
281+
}
279282
};
280283

281284
template <typename Self>
@@ -311,7 +314,7 @@ struct set_symmetric_difference_adaptor
311314
public:
312315
using value_type = std::common_type_t<value_t<Base1>, value_t<Base2>>;
313316

314-
inline static constexpr bool is_infinite = flux::infinite_sequence<Base1> ||
317+
inline static constexpr bool is_infinite = flux::infinite_sequence<Base1> ||
315318
flux::infinite_sequence<Base2>;
316319

317320
template <typename Self>
@@ -328,7 +331,7 @@ struct set_symmetric_difference_adaptor
328331
requires maybe_const_iterable<Self>
329332
static constexpr auto is_last(Self& self, cursor_type const& cur) -> bool
330333
{
331-
return flux::is_last(self.base1_, cur.base1_cursor) &&
334+
return flux::is_last(self.base1_, cur.base1_cursor) &&
332335
flux::is_last(self.base2_, cur.base2_cursor);
333336
}
334337

@@ -370,7 +373,9 @@ struct set_symmetric_difference_adaptor
370373
}
371374

372375
template <typename Self>
373-
requires maybe_const_iterable<Self> && bounded_sequence<Base1>
376+
requires maybe_const_iterable<Self> &&
377+
bounded_sequence<Base1> &&
378+
bounded_sequence<Base2>
374379
static constexpr auto last(Self& self) -> cursor_type
375380
{
376381
return cursor_type{flux::last(self.base1_), flux::last(self.base2_)};
@@ -428,7 +433,7 @@ struct set_intersection_adaptor
428433

429434
template <typename Self>
430435
static constexpr void update(Self& self, cursor_type& cur) {
431-
while(not flux::is_last(self.base1_, cur.base1_cursor) &&
436+
while(not flux::is_last(self.base1_, cur.base1_cursor) &&
432437
not flux::is_last(self.base2_, cur.base2_cursor))
433438
{
434439
auto r = std::invoke(self.cmp_, flux::read_at(self.base1_, cur.base1_cursor),
@@ -463,7 +468,7 @@ struct set_intersection_adaptor
463468
requires maybe_const_iterable<Self>
464469
static constexpr auto is_last(Self& self, cursor_type const& cur) -> bool
465470
{
466-
return flux::is_last(self.base1_, cur.base1_cursor) ||
471+
return flux::is_last(self.base1_, cur.base1_cursor) ||
467472
flux::is_last(self.base2_, cur.base2_cursor);
468473
}
469474

@@ -491,7 +496,7 @@ struct set_intersection_adaptor
491496
{
492497
return flux::move_at(self.base1_, cur.base1_cursor);
493498
}
494-
499+
495500
};
496501
};
497502

@@ -503,7 +508,7 @@ concept set_op_compatible =
503508

504509
struct set_union_fn {
505510
template <adaptable_sequence Seq1, adaptable_sequence Seq2, typename Cmp = std::compare_three_way>
506-
requires set_op_compatible<Seq1, Seq2> &&
511+
requires set_op_compatible<Seq1, Seq2> &&
507512
weak_ordering_for<Cmp, Seq1> &&
508513
weak_ordering_for<Cmp, Seq2>
509514
[[nodiscard]]

test/test_set_adaptors.cpp

+36-8
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
#include <array>
77
#include <utility>
8+
#include <vector>
89

910
#include "test_utils.hpp"
1011

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

113-
auto union_seq = flux::set_union(flux::ref(arr1), flux::ref(arr2),
114-
flux::proj(flux::cmp::compare, [] (auto v) { return v.first; }));
114+
auto union_seq
115+
= flux::set_union(flux::ref(arr1), flux::ref(arr2),
116+
flux::proj(flux::cmp::compare, [](auto v) { return v.first; }));
115117

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

270-
auto diff_seq = flux::set_difference(flux::ref(arr1), flux::ref(arr2),
271-
flux::proj(flux::cmp::compare, [] (auto v) { return v.first; }));
272+
auto diff_seq
273+
= flux::set_difference(flux::ref(arr1), flux::ref(arr2),
274+
flux::proj(flux::cmp::compare, [](auto v) { return v.first; }));
272275

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

415-
auto diff_seq = flux::set_symmetric_difference(flux::ref(arr1), flux::ref(arr2),
416-
flux::proj(flux::cmp::compare, [] (auto v) { return v.first; }));
418+
auto diff_seq = flux::set_symmetric_difference(
419+
flux::ref(arr1), flux::ref(arr2),
420+
flux::proj(flux::cmp::compare, [](auto v) { return v.first; }));
417421

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

561-
auto inter_seq = flux::set_intersection(flux::ref(arr1), flux::ref(arr2),
562-
flux::proj(flux::cmp::compare, [] (auto v) { return v.first; }));
565+
auto inter_seq = flux::set_intersection(
566+
flux::ref(arr1), flux::ref(arr2),
567+
flux::proj(flux::cmp::compare, [](auto v) { return v.first; }));
563568

564569
using T = decltype(inter_seq);
565570
static_assert(flux::sequence<T>);
@@ -607,6 +612,27 @@ static_assert(test_set_difference());
607612
static_assert(test_set_symmetric_difference());
608613
static_assert(test_set_intersection());
609614

615+
// https://github.com/tcbrindle/flux/issues/228
616+
constexpr bool issue_228()
617+
{
618+
std::array arr1 {0, 1, 2, 3, 4, 5};
619+
std::array arr2 {1, 3, 5, 6, 7};
620+
auto merged = flux::set_symmetric_difference(flux::ref(arr1), flux::ref(arr2));
621+
622+
STATIC_CHECK(flux::equal(merged, std::array {0, 2, 4, 6, 7}));
623+
624+
std::vector<int> out;
625+
626+
for (auto i : merged) {
627+
// crashes here
628+
out.push_back(i);
629+
}
630+
631+
STATIC_CHECK(check_equal(out, merged));
632+
633+
return true;
634+
}
635+
static_assert(issue_228());
610636
}
611637

612638
TEST_CASE("set_union")
@@ -625,6 +651,8 @@ TEST_CASE("set_symmetric_difference")
625651
{
626652
bool result = test_set_symmetric_difference();
627653
REQUIRE(result);
654+
result = issue_228();
655+
REQUIRE(result);
628656
}
629657

630658
TEST_CASE("set_intersection")

0 commit comments

Comments
 (0)