Commit 970a9caa by François Dumont

re PR libstdc++/61107 (stl_algo.h: std::__inplace_stable_partition() doesn't…

re PR libstdc++/61107 (stl_algo.h: std::__inplace_stable_partition() doesn't process the whole data range)

2014-11-11  François Dumont  <fdumont@gcc.gnu.org>

	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
parent ebf6d33b
2014-11-11 François Dumont <fdumont@gcc.gnu.org>
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.
2014-11-11 Francois-Xavier Coudert <fxcoudert@gcc.gnu.org> 2014-11-11 Francois-Xavier Coudert <fxcoudert@gcc.gnu.org>
PR target/63610 PR target/63610
......
...@@ -1512,34 +1512,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -1512,34 +1512,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// partition // partition
/// This is a helper function... /// This is a helper function...
/// Requires __len != 0 and !__pred(*__first),
/// same as __stable_partition_adaptive.
template<typename _ForwardIterator, typename _Predicate, typename _Distance>
_ForwardIterator
__inplace_stable_partition(_ForwardIterator __first,
_Predicate __pred, _Distance __len)
{
if (__len == 1)
return __first;
_ForwardIterator __middle = __first;
std::advance(__middle, __len / 2);
_ForwardIterator __left_split =
std::__inplace_stable_partition(__first, __pred, __len / 2);
// Advance past true-predicate values to satisfy this
// function's preconditions.
_Distance __right_len = __len - __len / 2;
_ForwardIterator __right_split =
std::__find_if_not_n(__middle, __right_len, __pred);
if (__right_len)
__right_split = std::__inplace_stable_partition(__middle,
__pred,
__right_len);
std::rotate(__left_split, __middle, __right_split);
std::advance(__left_split, std::distance(__middle, __right_split));
return __left_split;
}
/// This is a helper function...
/// Requires __first != __last and !__pred(__first) /// Requires __first != __last and !__pred(__first)
/// and __len == distance(__first, __last). /// and __len == distance(__first, __last).
/// ///
...@@ -1554,10 +1526,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -1554,10 +1526,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_Pointer __buffer, _Pointer __buffer,
_Distance __buffer_size) _Distance __buffer_size)
{ {
if (__len == 1)
return __first;
if (__len <= __buffer_size) if (__len <= __buffer_size)
{ {
_ForwardIterator __result1 = __first; _ForwardIterator __result1 = __first;
_Pointer __result2 = __buffer; _Pointer __result2 = __buffer;
// The precondition guarantees that !__pred(__first), so // The precondition guarantees that !__pred(__first), so
// move that element to the buffer before starting the loop. // move that element to the buffer before starting the loop.
// This ensures that we only call __pred once per element. // This ensures that we only call __pred once per element.
...@@ -1575,31 +1551,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -1575,31 +1551,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
*__result2 = _GLIBCXX_MOVE(*__first); *__result2 = _GLIBCXX_MOVE(*__first);
++__result2; ++__result2;
} }
_GLIBCXX_MOVE3(__buffer, __result2, __result1); _GLIBCXX_MOVE3(__buffer, __result2, __result1);
return __result1; return __result1;
} }
else
{ _ForwardIterator __middle = __first;
_ForwardIterator __middle = __first; std::advance(__middle, __len / 2);
std::advance(__middle, __len / 2); _ForwardIterator __left_split =
_ForwardIterator __left_split = std::__stable_partition_adaptive(__first, __middle, __pred,
std::__stable_partition_adaptive(__first, __middle, __pred, __len / 2, __buffer,
__len / 2, __buffer, __buffer_size);
__buffer_size);
// Advance past true-predicate values to satisfy this // Advance past true-predicate values to satisfy this
// function's preconditions. // function's preconditions.
_Distance __right_len = __len - __len / 2; _Distance __right_len = __len - __len / 2;
_ForwardIterator __right_split = _ForwardIterator __right_split =
std::__find_if_not_n(__middle, __right_len, __pred); std::__find_if_not_n(__middle, __right_len, __pred);
if (__right_len)
__right_split = if (__right_len)
std::__stable_partition_adaptive(__right_split, __last, __pred, __right_split =
__right_len, std::__stable_partition_adaptive(__right_split, __last, __pred,
__buffer, __buffer_size); __right_len,
std::rotate(__left_split, __middle, __right_split); __buffer, __buffer_size);
std::advance(__left_split, std::distance(__middle, __right_split));
return __left_split; std::rotate(__left_split, __middle, __right_split);
} std::advance(__left_split, std::distance(__middle, __right_split));
return __left_split;
} }
template<typename _ForwardIterator, typename _Predicate> template<typename _ForwardIterator, typename _Predicate>
...@@ -1618,16 +1596,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -1618,16 +1596,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_DistanceType; _DistanceType;
_Temporary_buffer<_ForwardIterator, _ValueType> __buf(__first, __last); _Temporary_buffer<_ForwardIterator, _ValueType> __buf(__first, __last);
if (__buf.size() > 0) return
return std::__stable_partition_adaptive(__first, __last, __pred,
std::__stable_partition_adaptive(__first, __last, __pred, _DistanceType(__buf.requested_size()),
_DistanceType(__buf.requested_size()), __buf.begin(),
__buf.begin(), _DistanceType(__buf.size()));
_DistanceType(__buf.size()));
else
return
std::__inplace_stable_partition(__first, __pred,
_DistanceType(__buf.requested_size()));
} }
/** /**
...@@ -2471,6 +2444,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -2471,6 +2444,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__gnu_cxx::__ops::__val_comp_iter(__comp)); __gnu_cxx::__ops::__val_comp_iter(__comp));
__len11 = std::distance(__first, __first_cut); __len11 = std::distance(__first, __first_cut);
} }
_BidirectionalIterator __new_middle _BidirectionalIterator __new_middle
= std::__rotate_adaptive(__first_cut, __middle, __second_cut, = std::__rotate_adaptive(__first_cut, __middle, __second_cut,
__len1 - __len11, __len22, __buffer, __len1 - __len11, __len22, __buffer,
...@@ -2496,12 +2470,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -2496,12 +2470,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ {
if (__len1 == 0 || __len2 == 0) if (__len1 == 0 || __len2 == 0)
return; return;
if (__len1 + __len2 == 2) if (__len1 + __len2 == 2)
{ {
if (__comp(__middle, __first)) if (__comp(__middle, __first))
std::iter_swap(__first, __middle); std::iter_swap(__first, __middle);
return; return;
} }
_BidirectionalIterator __first_cut = __first; _BidirectionalIterator __first_cut = __first;
_BidirectionalIterator __second_cut = __middle; _BidirectionalIterator __second_cut = __middle;
_Distance __len11 = 0; _Distance __len11 = 0;
...@@ -2524,6 +2500,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -2524,6 +2500,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__gnu_cxx::__ops::__val_comp_iter(__comp)); __gnu_cxx::__ops::__val_comp_iter(__comp));
__len11 = std::distance(__first, __first_cut); __len11 = std::distance(__first, __first_cut);
} }
std::rotate(__first_cut, __middle, __second_cut); std::rotate(__first_cut, __middle, __second_cut);
_BidirectionalIterator __new_middle = __first_cut; _BidirectionalIterator __new_middle = __first_cut;
std::advance(__new_middle, std::distance(__middle, __second_cut)); std::advance(__new_middle, std::distance(__middle, __second_cut));
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <algorithm> #include <algorithm>
#include <testsuite_hooks.h> #include <testsuite_hooks.h>
#include <testsuite_iterators.h> #include <testsuite_iterators.h>
#include <testsuite_new_operators.h>
using __gnu_test::test_container; using __gnu_test::test_container;
using __gnu_test::bidirectional_iterator_wrapper; using __gnu_test::bidirectional_iterator_wrapper;
...@@ -66,17 +67,27 @@ test3() ...@@ -66,17 +67,27 @@ test3()
{ {
bool test __attribute__((unused)) = true; bool test __attribute__((unused)) = true;
S s[4]; S s[8];
s[0].a = 0; s[0].a = 0;
s[1].a = 1; s[1].a = 1;
s[2].a = 0; s[2].a = 2;
s[3].a = 1; s[3].a = 3;
s[4].a = 0;
s[5].a = 1;
s[6].a = 2;
s[7].a = 3;
s[0].b = 0; s[0].b = 0;
s[1].b = 0; s[1].b = 1;
s[2].b = 1; s[2].b = 2;
s[3].b = 1; s[3].b = 3;
inplace_merge(s, s + 2, s + 4); s[4].b = 4;
VERIFY( s[0].b == 0 && s[1].b == 1 && s[2].b == 0 && s[3].b == 1 ); s[5].b = 5;
s[6].b = 6;
s[7].b = 7;
inplace_merge(s, s + 4, s + 8);
VERIFY( s[0].b == 0 && s[1].b == 4 && s[2].b == 1 && s[3].b == 5 );
} }
int int
...@@ -85,5 +96,15 @@ main() ...@@ -85,5 +96,15 @@ main()
test1(); test1();
test2(); test2();
test3(); test3();
__gnu_test::set_new_limit(sizeof(S) * 4);
test3();
__gnu_test::set_new_limit(sizeof(S));
test3();
__gnu_test::set_new_limit(0);
test3();
return 0; return 0;
} }
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <algorithm> #include <algorithm>
#include <functional> #include <functional>
#include <testsuite_new_operators.h>
#include <testsuite_hooks.h> #include <testsuite_hooks.h>
bool test __attribute__((unused)) = true; 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}; ...@@ -27,6 +28,9 @@ const int A[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17};
const int B[] = {2, 4, 6, 8, 10, 12, 14, 16, 1, 3, 5, 7, 9, 11, 13, 15, 17}; const int B[] = {2, 4, 6, 8, 10, 12, 14, 16, 1, 3, 5, 7, 9, 11, 13, 15, 17};
const int N = sizeof(A) / sizeof(int); const int N = sizeof(A) / sizeof(int);
// Index of the middle element that should be returned by the algo.
const int M = 8;
struct Pred struct Pred
{ {
bool bool
...@@ -36,20 +40,36 @@ struct Pred ...@@ -36,20 +40,36 @@ struct Pred
// 25.2.12 stable_partition() // 25.2.12 stable_partition()
void void
test02() test01()
{ {
using std::stable_partition; using std::stable_partition;
int s1[N]; int s1[N];
std::copy(A, A + N, s1); std::copy(A, A + N, s1);
stable_partition(s1, s1 + N, Pred()); VERIFY( stable_partition(s1, s1 + N, Pred()) == s1 + M );
VERIFY(std::equal(s1, s1 + N, B)); VERIFY( std::equal(s1, s1 + N, B) );
} }
int int
main() main()
{ {
test02(); test01();
// stable_partition rely on an internal buffer if possible. Try to limit the
// size of this buffer to see if algo is robust.
// Limit to half of the necessary buffer.
__gnu_test::set_new_limit(sizeof(A) / 2);
test01();
// Limit to just 1 element.
__gnu_test::set_new_limit(sizeof(int));
test01();
// Limit to 0
__gnu_test::set_new_limit(0);
test01();
return 0; return 0;
} }
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
// 25.3.1.2 [lib.stable.sort] // 25.3.1.2 [lib.stable.sort]
#include <algorithm> #include <algorithm>
#include <testsuite_new_operators.h>
#include <testsuite_hooks.h> #include <testsuite_hooks.h>
#include <testsuite_iterators.h> #include <testsuite_iterators.h>
...@@ -30,7 +31,7 @@ typedef test_container<int, random_access_iterator_wrapper> Container; ...@@ -30,7 +31,7 @@ typedef test_container<int, random_access_iterator_wrapper> Container;
void void
test1() test1()
{ {
int array[]={0}; int array[] = { 0 };
Container con(array, array); Container con(array, array);
stable_sort(con.begin(), con.end()); stable_sort(con.begin(), con.end());
} }
...@@ -38,13 +39,14 @@ test1() ...@@ -38,13 +39,14 @@ test1()
void void
test2() test2()
{ {
int array[] = {6, 5, 4, 3, 2, 1, 0}; int array[] = { 6, 5, 4, 3, 2, 1, 0 };
Container con(array, array + 7); Container con(array, array + 7);
stable_sort(con.begin(), con.end()); stable_sort(con.begin(), con.end());
VERIFY(array[0] == 0 && array[1] == 1 && array[2] == 2 && VERIFY(array[0] == 0 && array[1] == 1 && array[2] == 2 &&
array[3] == 3 && array[4] == 4 && array[5] == 5 && array[3] == 3 && array[4] == 4 && array[5] == 5 &&
array[6] == 6); array[6] == 6);
} }
struct S struct S
{ {
int i; int i;
...@@ -72,8 +74,7 @@ operator<(const S& s1, const S& s2) ...@@ -72,8 +74,7 @@ operator<(const S& s1, const S& s2)
void void
test3() test3()
{ {
S array[] = { -1, -2, 1, 2, -3 ,-5 ,3 , -4, 5, 4 };
S array[] = {-1, -2, 1, 2, -3 ,-5 ,3 , -4, 5, 4};
test_container<S, random_access_iterator_wrapper> con(array,array + 10); test_container<S, random_access_iterator_wrapper> con(array,array + 10);
stable_sort(con.begin(), con.end()); stable_sort(con.begin(), con.end());
for(int i = 0; i < 10; ++i) for(int i = 0; i < 10; ++i)
...@@ -85,5 +86,15 @@ main() ...@@ -85,5 +86,15 @@ main()
{ {
test1(); test1();
test2(); test2();
test3();
__gnu_test::set_new_limit(sizeof(S) * 5);
test3();
__gnu_test::set_new_limit(sizeof(S));
test3();
__gnu_test::set_new_limit(0);
test3(); test3();
} }
// -*- C++ -*-
// Utility subroutines for the C++ library testsuite.
//
// Copyright (C) 2000-2014 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
//
#ifndef _GLIBCXX_TESTSUITE_NEW_OPERATORS_H
#define _GLIBCXX_TESTSUITE_NEW_OPERATORS_H
#include <new>
namespace __gnu_test
{
std::size_t&
get_new_limit()
{
static std::size_t limit = 1024 * 1024;
return limit;
}
void
set_new_limit(std::size_t l)
{ get_new_limit() = l; }
}
void* operator new(std::size_t size) throw(std::bad_alloc)
{
if (size > __gnu_test::get_new_limit())
throw std::bad_alloc();
void* p = std::malloc(size);
if (!p)
throw std::bad_alloc();
return p;
}
void* operator new (std::size_t size, const std::nothrow_t&) throw()
{
if (size > __gnu_test::get_new_limit())
return 0;
return std::malloc(size);
}
void operator delete(void* p) throw()
{
if (p)
std::free(p);
}
#endif // _GLIBCXX_TESTSUITE_NEW_OPERATORS_H
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment