Skip to content

Commit a23c08c

Browse files
committed
Let timmerge and timsort return the end iterator
1 parent 2d48ebf commit a23c08c

File tree

3 files changed

+55
-21
lines changed

3 files changed

+55
-21
lines changed

README.md

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,18 @@ template <
3535
typename Projection = std::identity
3636
>
3737
requires std::sortable<Iterator, Compare, Projection>
38-
void timsort(Iterator first, Sentinel last,
39-
Compare compare={}, Projection projection={});
38+
auto timsort(Iterator first, Sentinel last,
39+
Compare compare={}, Projection projection={})
40+
-> Iterator;
4041

4142
template <
4243
std::ranges::random_access_range Range,
4344
typename Compare = std::ranges::less,
4445
typename Projection = std::identity
4546
>
4647
requires std::sortable<std::ranges::iterator_t<Range>, Compare, Projection>
47-
void timsort(Range &range, Compare compare={}, Projection projection={});
48+
auto timsort(Range &range, Compare compare={}, Projection projection={})
49+
-> std::ranges::borrowed_iterator_t<Range>;
4850

4951
// timmerge
5052

@@ -55,17 +57,19 @@ template <
5557
typename Projection = std::identity
5658
>
5759
requires std::sortable<Iterator, Compare, Projection>
58-
void timmerge(Iterator first, Iterator middle, Sentinel last,
59-
Compare compare={}, Projection projection={});
60+
auto timmerge(Iterator first, Iterator middle, Sentinel last,
61+
Compare compare={}, Projection projection={})
62+
-> Iterator;
6063

6164
template <
6265
std::ranges::random_access_range Range,
6366
typename Compare = std::ranges::less,
6467
typename Projection = std::identity
6568
>
6669
requires std::sortable<std::ranges::iterator_t<Range>, Compare, Projection>
67-
void timmerge(Range &&range, std::ranges::iterator_t<Range> middle,
70+
auto timmerge(Range &&range, std::ranges::iterator_t<Range> middle,
6871
Compare compare={}, Projection projection={})
72+
-> std::ranges::borrowed_iterator_t<Range>;
6973
```
7074
7175
## EXAMPLE

include/gfx/timsort.hpp

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -700,13 +700,16 @@ template <
700700
typename Projection = std::identity
701701
>
702702
requires std::sortable<Iterator, Compare, Projection>
703-
void timmerge(Iterator first, Iterator middle, Sentinel last,
704-
Compare comp={}, Projection proj={}) {
703+
auto timmerge(Iterator first, Iterator middle, Sentinel last,
704+
Compare comp={}, Projection proj={})
705+
-> Iterator
706+
{
705707
auto last_it = std::ranges::next(first, last);
706708
GFX_TIMSORT_AUDIT(std::is_sorted(first, middle, comp, proj) && "Precondition");
707709
GFX_TIMSORT_AUDIT(std::is_sorted(middle, last_it, comp, proj) && "Precondition");
708710
detail::TimSort<Iterator, Compare, Projection>::merge(first, middle, last_it, comp, proj);
709711
GFX_TIMSORT_AUDIT(std::is_sorted(first, last_it, comp, proj) && "Postcondition");
712+
return last_it;
710713
}
711714

712715
/**
@@ -719,10 +722,11 @@ template <
719722
typename Projection = std::identity
720723
>
721724
requires std::sortable<std::ranges::iterator_t<Range>, Compare, Projection>
722-
void timmerge(Range &&range, std::ranges::iterator_t<Range> middle,
725+
auto timmerge(Range &&range, std::ranges::iterator_t<Range> middle,
723726
Compare comp={}, Projection proj={})
727+
-> std::ranges::borrowed_iterator_t<Range>
724728
{
725-
gfx::timmerge(std::begin(range), middle, std::end(range), comp, proj);
729+
return gfx::timmerge(std::begin(range), middle, std::end(range), comp, proj);
726730
}
727731

728732
/**
@@ -735,11 +739,14 @@ template <
735739
typename Projection = std::identity
736740
>
737741
requires std::sortable<Iterator, Compare, Projection>
738-
void timsort(Iterator first, Sentinel last,
739-
Compare comp={}, Projection proj={}) {
742+
auto timsort(Iterator first, Sentinel last,
743+
Compare comp={}, Projection proj={})
744+
-> Iterator
745+
{
740746
auto last_it = std::ranges::next(first, last);
741747
detail::TimSort<Iterator, Compare, Projection>::sort(first, last_it, comp, proj);
742748
GFX_TIMSORT_AUDIT(std::is_sorted(first, last_it, comp, proj) && "Postcondition");
749+
return last_it;
743750
}
744751

745752
/**
@@ -751,8 +758,10 @@ template <
751758
typename Projection = std::identity
752759
>
753760
requires std::sortable<std::ranges::iterator_t<Range>, Compare, Projection>
754-
void timsort(Range &&range, Compare comp={}, Projection proj={}) {
755-
gfx::timsort(std::begin(range), std::end(range), comp, proj);
761+
auto timsort(Range &&range, Compare comp={}, Projection proj={})
762+
-> std::ranges::borrowed_iterator_t<Range>
763+
{
764+
return gfx::timsort(std::begin(range), std::end(range), comp, proj);
756765
}
757766

758767
} // namespace gfx

tests/cxx_20_tests.cpp

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <random>
99
#include <span>
1010
#include <vector>
11+
#include <utility>
1112
#include <catch2/catch_test_macros.hpp>
1213
#include <gfx/timsort.hpp>
1314
#include "test_helpers.hpp"
@@ -23,17 +24,33 @@ TEST_CASE( "support for temporary types" ) {
2324
gfx::timsort(middle, vec.end());
2425

2526
auto view = std::span(vec);
26-
gfx::timmerge(std::span(vec), view.begin() + 38);
27+
auto last_it = gfx::timmerge(std::span(vec), view.begin() + 38);
2728
CHECK(std::ranges::is_sorted(vec));
29+
CHECK(last_it == view.end());
2830
}
2931

3032
SECTION( "timsort over std::span" ) {
3133
std::vector<int> vec(50);
3234
std::iota(vec.begin(), vec.end(), -25);
3335
test_helpers::shuffle(vec);
3436

35-
gfx::timsort(std::span(vec));
37+
auto last_it = gfx::timsort(std::span(vec));
3638
CHECK(std::ranges::is_sorted(vec));
39+
CHECK(last_it == std::span(vec).end());
40+
}
41+
}
42+
43+
TEST_CASE( "dangling return type" ) {
44+
SECTION( "timmerge over temporary std::vector" ) {
45+
std::vector<int> vec(30, 5);
46+
auto last_it = gfx::timmerge(std::move(vec), vec.begin() + 14);
47+
STATIC_CHECK(std::is_same_v<decltype(last_it), std::ranges::dangling>);
48+
}
49+
50+
SECTION( "timsort over temporary std::vector" ) {
51+
std::vector<int> vec(50, 8);
52+
auto last_it = gfx::timsort(std::move(vec));
53+
STATIC_CHECK(std::is_same_v<decltype(last_it), std::ranges::dangling>);
3754
}
3855
}
3956

@@ -48,19 +65,23 @@ TEST_CASE( "support for sentinels" )
4865
gfx::timsort(vec.begin(), middle);
4966
gfx::timsort(middle, vec.end());
5067

51-
gfx::timmerge(std::counted_iterator(vec.begin(), 85),
52-
std::counted_iterator(middle, 85 - 38),
53-
std::default_sentinel);
68+
auto last_it = gfx::timmerge(std::counted_iterator(vec.begin(), 85),
69+
std::counted_iterator(middle, 85 - 38),
70+
std::default_sentinel);
5471
CHECK(std::is_sorted(vec.begin(), vec.begin() + 85));
72+
CHECK(last_it == std::counted_iterator(vec.begin() + 85, 0));
73+
CHECK(last_it == std::default_sentinel);
5574
}
5675

5776
SECTION( "timsort with sentinel" ) {
5877
std::vector<int> vec(100);
5978
std::iota(vec.begin(), vec.end(), -25);
6079
test_helpers::shuffle(vec);
6180

62-
gfx::timsort(std::counted_iterator(vec.begin(), 85),
63-
std::default_sentinel);
81+
auto last_it = gfx::timsort(std::counted_iterator(vec.begin(), 85),
82+
std::default_sentinel);
6483
CHECK(std::is_sorted(vec.begin(), vec.begin() + 85));
84+
CHECK(last_it == std::counted_iterator(vec.begin() + 85, 0));
85+
CHECK(last_it == std::default_sentinel);
6586
}
6687
}

0 commit comments

Comments
 (0)