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
This commit is contained in:
François Dumont 2014-11-11 21:21:10 +00:00
parent ebf6d33b73
commit 970a9caa49
6 changed files with 189 additions and 79 deletions

View File

@ -1,3 +1,15 @@
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>
PR target/63610

View File

@ -1511,34 +1511,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// partition
/// 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)
/// and __len == distance(__first, __last).
@ -1554,10 +1526,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_Pointer __buffer,
_Distance __buffer_size)
{
if (__len == 1)
return __first;
if (__len <= __buffer_size)
{
_ForwardIterator __result1 = __first;
_Pointer __result2 = __buffer;
// The precondition guarantees that !__pred(__first), so
// move that element to the buffer before starting the loop.
// This ensures that we only call __pred once per element.
@ -1575,31 +1551,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
*__result2 = _GLIBCXX_MOVE(*__first);
++__result2;
}
_GLIBCXX_MOVE3(__buffer, __result2, __result1);
return __result1;
}
else
{
_ForwardIterator __middle = __first;
std::advance(__middle, __len / 2);
_ForwardIterator __left_split =
std::__stable_partition_adaptive(__first, __middle, __pred,
__len / 2, __buffer,
__buffer_size);
// 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::__stable_partition_adaptive(__right_split, __last, __pred,
__right_len,
__buffer, __buffer_size);
std::rotate(__left_split, __middle, __right_split);
std::advance(__left_split, std::distance(__middle, __right_split));
return __left_split;
}
_ForwardIterator __middle = __first;
std::advance(__middle, __len / 2);
_ForwardIterator __left_split =
std::__stable_partition_adaptive(__first, __middle, __pred,
__len / 2, __buffer,
__buffer_size);
// 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::__stable_partition_adaptive(__right_split, __last, __pred,
__right_len,
__buffer, __buffer_size);
std::rotate(__left_split, __middle, __right_split);
std::advance(__left_split, std::distance(__middle, __right_split));
return __left_split;
}
template<typename _ForwardIterator, typename _Predicate>
@ -1618,16 +1596,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_DistanceType;
_Temporary_buffer<_ForwardIterator, _ValueType> __buf(__first, __last);
if (__buf.size() > 0)
return
std::__stable_partition_adaptive(__first, __last, __pred,
_DistanceType(__buf.requested_size()),
__buf.begin(),
_DistanceType(__buf.size()));
else
return
std::__inplace_stable_partition(__first, __pred,
_DistanceType(__buf.requested_size()));
return
std::__stable_partition_adaptive(__first, __last, __pred,
_DistanceType(__buf.requested_size()),
__buf.begin(),
_DistanceType(__buf.size()));
}
/**
@ -2471,6 +2444,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__gnu_cxx::__ops::__val_comp_iter(__comp));
__len11 = std::distance(__first, __first_cut);
}
_BidirectionalIterator __new_middle
= std::__rotate_adaptive(__first_cut, __middle, __second_cut,
__len1 - __len11, __len22, __buffer,
@ -2496,12 +2470,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{
if (__len1 == 0 || __len2 == 0)
return;
if (__len1 + __len2 == 2)
{
if (__comp(__middle, __first))
std::iter_swap(__first, __middle);
return;
}
_BidirectionalIterator __first_cut = __first;
_BidirectionalIterator __second_cut = __middle;
_Distance __len11 = 0;
@ -2524,6 +2500,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__gnu_cxx::__ops::__val_comp_iter(__comp));
__len11 = std::distance(__first, __first_cut);
}
std::rotate(__first_cut, __middle, __second_cut);
_BidirectionalIterator __new_middle = __first_cut;
std::advance(__new_middle, std::distance(__middle, __second_cut));

View File

@ -20,6 +20,7 @@
#include <algorithm>
#include <testsuite_hooks.h>
#include <testsuite_iterators.h>
#include <testsuite_new_operators.h>
using __gnu_test::test_container;
using __gnu_test::bidirectional_iterator_wrapper;
@ -66,17 +67,27 @@ test3()
{
bool test __attribute__((unused)) = true;
S s[4];
S s[8];
s[0].a = 0;
s[1].a = 1;
s[2].a = 0;
s[3].a = 1;
s[2].a = 2;
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[1].b = 0;
s[2].b = 1;
s[3].b = 1;
inplace_merge(s, s + 2, s + 4);
VERIFY( s[0].b == 0 && s[1].b == 1 && s[2].b == 0 && s[3].b == 1 );
s[1].b = 1;
s[2].b = 2;
s[3].b = 3;
s[4].b = 4;
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
@ -85,5 +96,15 @@ main()
test1();
test2();
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;
}

View File

@ -19,6 +19,7 @@
#include <algorithm>
#include <functional>
#include <testsuite_new_operators.h>
#include <testsuite_hooks.h>
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};
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);
// Index of the middle element that should be returned by the algo.
const int M = 8;
struct Pred
{
bool
@ -36,20 +40,36 @@ struct Pred
// 25.2.12 stable_partition()
void
test02()
test01()
{
using std::stable_partition;
using std::stable_partition;
int s1[N];
std::copy(A, A + N, s1);
int s1[N];
std::copy(A, A + N, s1);
stable_partition(s1, s1 + N, Pred());
VERIFY(std::equal(s1, s1 + N, B));
VERIFY( stable_partition(s1, s1 + N, Pred()) == s1 + M );
VERIFY( std::equal(s1, s1 + N, B) );
}
int
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;
}

View File

@ -18,6 +18,7 @@
// 25.3.1.2 [lib.stable.sort]
#include <algorithm>
#include <testsuite_new_operators.h>
#include <testsuite_hooks.h>
#include <testsuite_iterators.h>
@ -30,7 +31,7 @@ typedef test_container<int, random_access_iterator_wrapper> Container;
void
test1()
{
int array[]={0};
int array[] = { 0 };
Container con(array, array);
stable_sort(con.begin(), con.end());
}
@ -38,13 +39,14 @@ test1()
void
test2()
{
int array[] = {6, 5, 4, 3, 2, 1, 0};
int array[] = { 6, 5, 4, 3, 2, 1, 0 };
Container con(array, array + 7);
stable_sort(con.begin(), con.end());
VERIFY(array[0] == 0 && array[1] == 1 && array[2] == 2 &&
array[3] == 3 && array[4] == 4 && array[5] == 5 &&
array[6] == 6);
}
struct S
{
int i;
@ -72,8 +74,7 @@ operator<(const S& s1, const S& s2)
void
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);
stable_sort(con.begin(), con.end());
for(int i = 0; i < 10; ++i)
@ -85,5 +86,15 @@ main()
{
test1();
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();
}

View File

@ -0,0 +1,69 @@
// -*- 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