Skip to content

Commit

Permalink
Fix invalid iterators in grailsort strategy 3 (#183)
Browse files Browse the repository at this point in the history
Grailsort creates invalid pointers here and there that are never
dereferenced, so generally don't cause any issues. However, forming
invalid iterators like that might cause issues, and MSVC debug iterators
do trip on grailsort.

This commit only fixes "strategy 3": when the algorithm can't find at
least 4 unique keys in the collection.
  • Loading branch information
Morwenn committed Feb 16, 2021
1 parent c3cde9f commit a5db222
Showing 1 changed file with 12 additions and 9 deletions.
21 changes: 12 additions & 9 deletions include/cpp-sort/detail/grail_sort.h
Original file line number Diff line number Diff line change
Expand Up @@ -623,26 +623,29 @@ namespace grail

template<typename RandomAccessIterator, typename Compare, typename Projection>
auto lazy_stable_sort(RandomAccessIterator first, RandomAccessIterator last,
Compare compare, Projection projection)
Compare compare, Projection projection)
-> void
{
using difference_type = difference_type_t<RandomAccessIterator>;
using utility::iter_swap;
auto&& proj = utility::as_function(projection);

for (auto it = std::next(first) ; it < last ; it += 2) {
if (compare(proj(*std::prev(it)), proj(*it)) > 0) {
iter_swap(std::prev(it), it);
auto size = last - first;
auto end_loop = size % 2 == 0 ? last : std::prev(last);
for (auto it = first ; it != end_loop ; it += 2) {
if (compare(proj(*it), proj(*std::next(it))) > 0) {
iter_swap(it, std::next(it));
}
}

auto size = last - first;
for (difference_type h = 2 ; h < size ; h *= 2) {
auto p0 = first;
auto p1 = last - 2 * h;
while (p0 <= p1) {
merge_without_buffer(p0, p0 + h, p0 + (h + h), compare, projection);
p0 += 2 * h;
if (2 * h <= size) {
auto p1 = last - 2 * h;
while (p0 <= p1) {
merge_without_buffer(p0, p0 + h, p0 + (h + h), compare, projection);
p0 += 2 * h;
}
}
int rest = last - p0;
if (rest > h) {
Expand Down

0 comments on commit a5db222

Please sign in to comment.