Skip to content

Commit 970a9ca

Browse files
committed
re PR libstdc++/61107 (stl_algo.h: std::__inplace_stable_partition() doesn't process the whole data range)
2014-11-11 François Dumont <[email protected]> PR libstdc++/61107 * include/bits/stl_algo.h (__inplace_stable_partition): Delete. (__stable_partition_adaptive): Return __first if range length is 1. (__stable_partition): Adapt. * testsuite/util/testsuite_new_operators.h: New. * testsuite/25_algorithms/stable_sort/1.cc: Test algo in simulated constraint memory context. * testsuite/25_algorithms/inplace_merge/1.cc: Likewise. * testsuite/25_algorithms/stable_partition/1.cc: Likewise. From-SVN: r217370
1 parent ebf6d33 commit 970a9ca

File tree

6 files changed

+189
-79
lines changed

6 files changed

+189
-79
lines changed

libstdc++-v3/ChangeLog

+12
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,15 @@
1+
2014-11-11 François Dumont <[email protected]>
2+
3+
PR libstdc++/61107
4+
* include/bits/stl_algo.h (__inplace_stable_partition): Delete.
5+
(__stable_partition_adaptive): Return __first if range length is 1.
6+
(__stable_partition): Adapt.
7+
* testsuite/util/testsuite_new_operators.h: New.
8+
* testsuite/25_algorithms/stable_sort/1.cc: Test algo in simulated
9+
constraint memory context.
10+
* testsuite/25_algorithms/inplace_merge/1.cc: Likewise.
11+
* testsuite/25_algorithms/stable_partition/1.cc: Likewise.
12+
113
2014-11-11 Francois-Xavier Coudert <[email protected]>
214

315
PR target/63610

libstdc++-v3/include/bits/stl_algo.h

+37-60
Original file line numberDiff line numberDiff line change
@@ -1511,34 +1511,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
15111511

15121512
// partition
15131513

1514-
/// This is a helper function...
1515-
/// Requires __len != 0 and !__pred(*__first),
1516-
/// same as __stable_partition_adaptive.
1517-
template<typename _ForwardIterator, typename _Predicate, typename _Distance>
1518-
_ForwardIterator
1519-
__inplace_stable_partition(_ForwardIterator __first,
1520-
_Predicate __pred, _Distance __len)
1521-
{
1522-
if (__len == 1)
1523-
return __first;
1524-
_ForwardIterator __middle = __first;
1525-
std::advance(__middle, __len / 2);
1526-
_ForwardIterator __left_split =
1527-
std::__inplace_stable_partition(__first, __pred, __len / 2);
1528-
// Advance past true-predicate values to satisfy this
1529-
// function's preconditions.
1530-
_Distance __right_len = __len - __len / 2;
1531-
_ForwardIterator __right_split =
1532-
std::__find_if_not_n(__middle, __right_len, __pred);
1533-
if (__right_len)
1534-
__right_split = std::__inplace_stable_partition(__middle,
1535-
__pred,
1536-
__right_len);
1537-
std::rotate(__left_split, __middle, __right_split);
1538-
std::advance(__left_split, std::distance(__middle, __right_split));
1539-
return __left_split;
1540-
}
1541-
15421514
/// This is a helper function...
15431515
/// Requires __first != __last and !__pred(__first)
15441516
/// and __len == distance(__first, __last).
@@ -1554,10 +1526,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
15541526
_Pointer __buffer,
15551527
_Distance __buffer_size)
15561528
{
1529+
if (__len == 1)
1530+
return __first;
1531+
15571532
if (__len <= __buffer_size)
15581533
{
15591534
_ForwardIterator __result1 = __first;
15601535
_Pointer __result2 = __buffer;
1536+
15611537
// The precondition guarantees that !__pred(__first), so
15621538
// move that element to the buffer before starting the loop.
15631539
// This ensures that we only call __pred once per element.
@@ -1575,31 +1551,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
15751551
*__result2 = _GLIBCXX_MOVE(*__first);
15761552
++__result2;
15771553
}
1554+
15781555
_GLIBCXX_MOVE3(__buffer, __result2, __result1);
15791556
return __result1;
15801557
}
1581-
else
1582-
{
1583-
_ForwardIterator __middle = __first;
1584-
std::advance(__middle, __len / 2);
1585-
_ForwardIterator __left_split =
1586-
std::__stable_partition_adaptive(__first, __middle, __pred,
1587-
__len / 2, __buffer,
1588-
__buffer_size);
1589-
// Advance past true-predicate values to satisfy this
1590-
// function's preconditions.
1591-
_Distance __right_len = __len - __len / 2;
1592-
_ForwardIterator __right_split =
1593-
std::__find_if_not_n(__middle, __right_len, __pred);
1594-
if (__right_len)
1595-
__right_split =
1596-
std::__stable_partition_adaptive(__right_split, __last, __pred,
1597-
__right_len,
1598-
__buffer, __buffer_size);
1599-
std::rotate(__left_split, __middle, __right_split);
1600-
std::advance(__left_split, std::distance(__middle, __right_split));
1601-
return __left_split;
1602-
}
1558+
1559+
_ForwardIterator __middle = __first;
1560+
std::advance(__middle, __len / 2);
1561+
_ForwardIterator __left_split =
1562+
std::__stable_partition_adaptive(__first, __middle, __pred,
1563+
__len / 2, __buffer,
1564+
__buffer_size);
1565+
1566+
// Advance past true-predicate values to satisfy this
1567+
// function's preconditions.
1568+
_Distance __right_len = __len - __len / 2;
1569+
_ForwardIterator __right_split =
1570+
std::__find_if_not_n(__middle, __right_len, __pred);
1571+
1572+
if (__right_len)
1573+
__right_split =
1574+
std::__stable_partition_adaptive(__right_split, __last, __pred,
1575+
__right_len,
1576+
__buffer, __buffer_size);
1577+
1578+
std::rotate(__left_split, __middle, __right_split);
1579+
std::advance(__left_split, std::distance(__middle, __right_split));
1580+
return __left_split;
16031581
}
16041582

16051583
template<typename _ForwardIterator, typename _Predicate>
@@ -1618,16 +1596,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
16181596
_DistanceType;
16191597

16201598
_Temporary_buffer<_ForwardIterator, _ValueType> __buf(__first, __last);
1621-
if (__buf.size() > 0)
1622-
return
1623-
std::__stable_partition_adaptive(__first, __last, __pred,
1624-
_DistanceType(__buf.requested_size()),
1625-
__buf.begin(),
1626-
_DistanceType(__buf.size()));
1627-
else
1628-
return
1629-
std::__inplace_stable_partition(__first, __pred,
1630-
_DistanceType(__buf.requested_size()));
1599+
return
1600+
std::__stable_partition_adaptive(__first, __last, __pred,
1601+
_DistanceType(__buf.requested_size()),
1602+
__buf.begin(),
1603+
_DistanceType(__buf.size()));
16311604
}
16321605

16331606
/**
@@ -2471,6 +2444,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
24712444
__gnu_cxx::__ops::__val_comp_iter(__comp));
24722445
__len11 = std::distance(__first, __first_cut);
24732446
}
2447+
24742448
_BidirectionalIterator __new_middle
24752449
= std::__rotate_adaptive(__first_cut, __middle, __second_cut,
24762450
__len1 - __len11, __len22, __buffer,
@@ -2496,12 +2470,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
24962470
{
24972471
if (__len1 == 0 || __len2 == 0)
24982472
return;
2473+
24992474
if (__len1 + __len2 == 2)
25002475
{
25012476
if (__comp(__middle, __first))
25022477
std::iter_swap(__first, __middle);
25032478
return;
25042479
}
2480+
25052481
_BidirectionalIterator __first_cut = __first;
25062482
_BidirectionalIterator __second_cut = __middle;
25072483
_Distance __len11 = 0;
@@ -2524,6 +2500,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
25242500
__gnu_cxx::__ops::__val_comp_iter(__comp));
25252501
__len11 = std::distance(__first, __first_cut);
25262502
}
2503+
25272504
std::rotate(__first_cut, __middle, __second_cut);
25282505
_BidirectionalIterator __new_middle = __first_cut;
25292506
std::advance(__new_middle, std::distance(__middle, __second_cut));

libstdc++-v3/testsuite/25_algorithms/inplace_merge/1.cc

+29-8
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <algorithm>
2121
#include <testsuite_hooks.h>
2222
#include <testsuite_iterators.h>
23+
#include <testsuite_new_operators.h>
2324

2425
using __gnu_test::test_container;
2526
using __gnu_test::bidirectional_iterator_wrapper;
@@ -66,17 +67,27 @@ test3()
6667
{
6768
bool test __attribute__((unused)) = true;
6869

69-
S s[4];
70+
S s[8];
7071
s[0].a = 0;
7172
s[1].a = 1;
72-
s[2].a = 0;
73-
s[3].a = 1;
73+
s[2].a = 2;
74+
s[3].a = 3;
75+
s[4].a = 0;
76+
s[5].a = 1;
77+
s[6].a = 2;
78+
s[7].a = 3;
79+
7480
s[0].b = 0;
75-
s[1].b = 0;
76-
s[2].b = 1;
77-
s[3].b = 1;
78-
inplace_merge(s, s + 2, s + 4);
79-
VERIFY( s[0].b == 0 && s[1].b == 1 && s[2].b == 0 && s[3].b == 1 );
81+
s[1].b = 1;
82+
s[2].b = 2;
83+
s[3].b = 3;
84+
s[4].b = 4;
85+
s[5].b = 5;
86+
s[6].b = 6;
87+
s[7].b = 7;
88+
89+
inplace_merge(s, s + 4, s + 8);
90+
VERIFY( s[0].b == 0 && s[1].b == 4 && s[2].b == 1 && s[3].b == 5 );
8091
}
8192

8293
int
@@ -85,5 +96,15 @@ main()
8596
test1();
8697
test2();
8798
test3();
99+
100+
__gnu_test::set_new_limit(sizeof(S) * 4);
101+
test3();
102+
103+
__gnu_test::set_new_limit(sizeof(S));
104+
test3();
105+
106+
__gnu_test::set_new_limit(0);
107+
test3();
108+
88109
return 0;
89110
}

libstdc++-v3/testsuite/25_algorithms/stable_partition/1.cc

+27-7
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
#include <algorithm>
2121
#include <functional>
22+
#include <testsuite_new_operators.h>
2223
#include <testsuite_hooks.h>
2324

2425
bool test __attribute__((unused)) = true;
@@ -27,6 +28,9 @@ const int A[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17};
2728
const int B[] = {2, 4, 6, 8, 10, 12, 14, 16, 1, 3, 5, 7, 9, 11, 13, 15, 17};
2829
const int N = sizeof(A) / sizeof(int);
2930

31+
// Index of the middle element that should be returned by the algo.
32+
const int M = 8;
33+
3034
struct Pred
3135
{
3236
bool
@@ -36,20 +40,36 @@ struct Pred
3640

3741
// 25.2.12 stable_partition()
3842
void
39-
test02()
43+
test01()
4044
{
41-
using std::stable_partition;
45+
using std::stable_partition;
4246

43-
int s1[N];
44-
std::copy(A, A + N, s1);
47+
int s1[N];
48+
std::copy(A, A + N, s1);
4549

46-
stable_partition(s1, s1 + N, Pred());
47-
VERIFY(std::equal(s1, s1 + N, B));
50+
VERIFY( stable_partition(s1, s1 + N, Pred()) == s1 + M );
51+
VERIFY( std::equal(s1, s1 + N, B) );
4852
}
4953

5054
int
5155
main()
5256
{
53-
test02();
57+
test01();
58+
59+
// stable_partition rely on an internal buffer if possible. Try to limit the
60+
// size of this buffer to see if algo is robust.
61+
62+
// Limit to half of the necessary buffer.
63+
__gnu_test::set_new_limit(sizeof(A) / 2);
64+
test01();
65+
66+
// Limit to just 1 element.
67+
__gnu_test::set_new_limit(sizeof(int));
68+
test01();
69+
70+
// Limit to 0
71+
__gnu_test::set_new_limit(0);
72+
test01();
73+
5474
return 0;
5575
}

libstdc++-v3/testsuite/25_algorithms/stable_sort/1.cc

+15-4
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
// 25.3.1.2 [lib.stable.sort]
1919

2020
#include <algorithm>
21+
#include <testsuite_new_operators.h>
2122
#include <testsuite_hooks.h>
2223
#include <testsuite_iterators.h>
2324

@@ -30,21 +31,22 @@ typedef test_container<int, random_access_iterator_wrapper> Container;
3031
void
3132
test1()
3233
{
33-
int array[]={0};
34+
int array[] = { 0 };
3435
Container con(array, array);
3536
stable_sort(con.begin(), con.end());
3637
}
3738

3839
void
3940
test2()
4041
{
41-
int array[] = {6, 5, 4, 3, 2, 1, 0};
42+
int array[] = { 6, 5, 4, 3, 2, 1, 0 };
4243
Container con(array, array + 7);
4344
stable_sort(con.begin(), con.end());
4445
VERIFY(array[0] == 0 && array[1] == 1 && array[2] == 2 &&
4546
array[3] == 3 && array[4] == 4 && array[5] == 5 &&
4647
array[6] == 6);
4748
}
49+
4850
struct S
4951
{
5052
int i;
@@ -72,8 +74,7 @@ operator<(const S& s1, const S& s2)
7274
void
7375
test3()
7476
{
75-
76-
S array[] = {-1, -2, 1, 2, -3 ,-5 ,3 , -4, 5, 4};
77+
S array[] = { -1, -2, 1, 2, -3 ,-5 ,3 , -4, 5, 4 };
7778
test_container<S, random_access_iterator_wrapper> con(array,array + 10);
7879
stable_sort(con.begin(), con.end());
7980
for(int i = 0; i < 10; ++i)
@@ -85,5 +86,15 @@ main()
8586
{
8687
test1();
8788
test2();
89+
90+
test3();
91+
92+
__gnu_test::set_new_limit(sizeof(S) * 5);
93+
test3();
94+
95+
__gnu_test::set_new_limit(sizeof(S));
96+
test3();
97+
98+
__gnu_test::set_new_limit(0);
8899
test3();
89100
}

0 commit comments

Comments
 (0)