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:
parent
ebf6d33b73
commit
970a9caa49
@ -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
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
69
libstdc++-v3/testsuite/util/testsuite_new_operators.h
Normal file
69
libstdc++-v3/testsuite/util/testsuite_new_operators.h
Normal 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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user