Skip to content

Commit

Permalink
Fixes #45 ("Sort/merge bugs that affect boost::container::flat_map")
Browse files Browse the repository at this point in the history
  • Loading branch information
igaztanaga committed Nov 3, 2021
1 parent 70623d0 commit a51c5cc
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 36 deletions.
7 changes: 7 additions & 0 deletions doc/move.qbk
Expand Up @@ -802,6 +802,13 @@ Special thanks to:

[section:release_notes Release Notes]

[section:release_notes_boost_1_78 Boost 1.78 Release]

* Fixed bugs:
* [@https://github.com/boostorg/move/issues/45 Git Issue #45: ['"Sort/merge bugs that affect boost::container::flat_map"]].

[endsect]

[section:release_notes_boost_1_77 Boost 1.77 Release]

* Fixed bugs:
Expand Down
4 changes: 2 additions & 2 deletions include/boost/move/algo/adaptive_sort.hpp
Expand Up @@ -453,9 +453,9 @@ bool adaptive_sort_build_params
l_build_buf = size_type(l_intbuf*2);
n_keys = l_intbuf;
}
else if(collected == (n_min_ideal_keys+l_intbuf)){
else if(collected >= (n_min_ideal_keys+l_intbuf)){
l_build_buf = l_intbuf;
n_keys = n_min_ideal_keys;
n_keys = size_type(collected - l_intbuf);
}
//If collected keys are not enough, try to fix n_keys and l_intbuf. If no fix
//is possible (due to very low unique keys), then go to a slow sort based on rotations.
Expand Down
61 changes: 30 additions & 31 deletions include/boost/move/algo/detail/merge.hpp
Expand Up @@ -863,49 +863,48 @@ template<typename BidirectionalIterator,
typedef typename iterator_traits<BidirectionalIterator>::size_type size_type;
//trivial cases
if (!len2 || !len1) {
return;
// no-op
}
else if (len1 <= buffer_size || len2 <= buffer_size)
{
else if (len1 <= buffer_size || len2 <= buffer_size) {
range_xbuf<Pointer, size_type, move_op> rxbuf(buffer, buffer + buffer_size);
buffered_merge(first, middle, last, comp, rxbuf);
}
else if (size_type(len1 + len2) == 2u) {
if (comp(*middle, *first))
adl_move_swap(*first, *middle);
return;
}
else if (size_type(len1 + len2) < MergeBufferlessONLogNRotationThreshold) {
merge_bufferless_ON2(first, middle, last, comp);
return;
}
BidirectionalIterator first_cut = first;
BidirectionalIterator second_cut = middle;
size_type len11 = 0;
size_type len22 = 0;
if (len1 > len2) //(len1 < len2)
{
len11 = len1 / 2;
first_cut += len11;
second_cut = boost::movelib::lower_bound(middle, last, *first_cut, comp);
len22 = size_type(second_cut - middle);
else {
BidirectionalIterator first_cut = first;
BidirectionalIterator second_cut = middle;
size_type len11 = 0;
size_type len22 = 0;
if (len1 > len2) //(len1 < len2)
{
len11 = len1 / 2;
first_cut += len11;
second_cut = boost::movelib::lower_bound(middle, last, *first_cut, comp);
len22 = size_type(second_cut - middle);
}
else
{
len22 = len2 / 2;
second_cut += len22;
first_cut = boost::movelib::upper_bound(first, middle, *second_cut, comp);
len11 = size_type(first_cut - first);
}

BidirectionalIterator new_middle
= rotate_adaptive(first_cut, middle, second_cut,
size_type(len1 - len11), len22, buffer,
buffer_size);
merge_adaptive_ONlogN_recursive(first, first_cut, new_middle, len11,
len22, buffer, buffer_size, comp);
merge_adaptive_ONlogN_recursive(new_middle, second_cut, last,
size_type(len1 - len11), size_type(len2 - len22), buffer, buffer_size, comp);
}
else
{
len22 = len2 / 2;
second_cut += len22;
first_cut = boost::movelib::upper_bound(first, middle, *second_cut, comp);
len11 = size_type(first_cut - first);
}

BidirectionalIterator new_middle
= rotate_adaptive(first_cut, middle, second_cut,
size_type(len1 - len11), len22, buffer,
buffer_size);
merge_adaptive_ONlogN_recursive(first, first_cut, new_middle, len11,
len22, buffer, buffer_size, comp);
merge_adaptive_ONlogN_recursive(new_middle, second_cut, last,
size_type(len1 - len11), size_type(len2 - len22), buffer, buffer_size, comp);
}


Expand Down
12 changes: 9 additions & 3 deletions test/adaptive_sort_test.cpp
Expand Up @@ -74,9 +74,15 @@ int main()
instantiate_smalldiff_iterators();

const std::size_t NIter = 100;
test_random_shuffled<order_move_type>(10001, 3, NIter);
test_random_shuffled<order_move_type>(10001, 65, NIter);
test_random_shuffled<order_move_type>(10001, 101, NIter);
//Below absolute minimal unique values
test_random_shuffled<order_move_type>(10001, 3, NIter);
//Above absolute minimal unique values, below internal buffer
test_random_shuffled<order_move_type>(10001, 65, NIter);
//Enough keys for internal buffer but below minimal keys
test_random_shuffled<order_move_type>(10001, 101, NIter);
//Enough keys for internal buffer and above minimal keys
test_random_shuffled<order_move_type>(10001, 200, NIter);
//Enough keys for internal buffer, and full keys
test_random_shuffled<order_move_type>(10001, 1023, NIter);
test_random_shuffled<order_move_type>(10001, 4095, NIter);
test_random_shuffled<order_move_type>(10001, 0, NIter);
Expand Down

0 comments on commit a51c5cc

Please sign in to comment.