re PR libstdc++/34595 (std::copy copies the output iterator before assigning)

2007-12-26  Paolo Carlini  <pcarlini@suse.de>

	PR libstdc++/34595
	* include/bits/stl_algobase.h (struct __cm_assign): Remove.
	(struct __copy_move<true, false, _Category>,
	struct __copy_move<true, false, random_access_iterator_tag>,
	struct __copy_move_backward<true, false, _Category>,
	struct __copy_move_backward<true, false, random_access_iterator_tag>):
	Add.
	(struct __copy_move, struct __copy_move_backward,
	struct __copy_move<false, false, random_access_iterator_tag>,
	struct __copy_move_backward<false, false, random_access_iterator_tag>):
	Adjust.
	* testsuite/25_algorithms/copy/34595.C: New.

From-SVN: r131188
This commit is contained in:
Paolo Carlini 2007-12-26 21:58:49 +00:00 committed by Paolo Carlini
parent 3dfb41c564
commit 5f6d5f0af6
3 changed files with 146 additions and 31 deletions

View File

@ -1,3 +1,18 @@
2007-12-26 Paolo Carlini <pcarlini@suse.de>
PR libstdc++/34595
* include/bits/stl_algobase.h (struct __cm_assign): Remove.
(struct __copy_move<true, false, _Category>,
struct __copy_move<true, false, random_access_iterator_tag>,
struct __copy_move_backward<true, false, _Category>,
struct __copy_move_backward<true, false, random_access_iterator_tag>):
Add.
(struct __copy_move, struct __copy_move_backward,
struct __copy_move<false, false, random_access_iterator_tag>,
struct __copy_move_backward<false, false, random_access_iterator_tag>):
Adjust.
* testsuite/25_algorithms/copy/34595.C: New.
2007-12-26 Chris Fairles <chris.fairles@gmail.com>
Paolo Carlini <pcarlini@suse.de>

View File

@ -295,34 +295,13 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
{ return __it.base(); }
};
// Used in __copy_move and __copy_move_backward below.
template<bool _IsMove>
struct __cm_assign
{
template<typename _IteratorL, typename _IteratorR>
static void
__a(_IteratorL __lhs, _IteratorR __rhs)
{ *__lhs = *__rhs; }
};
#ifdef __GXX_EXPERIMENTAL_CXX0X__
template<>
struct __cm_assign<true>
{
template<typename _IteratorL, typename _IteratorR>
static void
__a(_IteratorL __lhs, _IteratorR __rhs)
{ *__lhs = std::move(*__rhs); }
};
#endif
// All of these auxiliary structs serve two purposes. (1) Replace
// calls to copy with memmove whenever possible. (Memmove, not memcpy,
// because the input and output ranges are permitted to overlap.)
// (2) If we're using random access iterators, then write the loop as
// a for loop with an explicit count.
template<bool _IsMove, bool, typename>
template<bool, bool, typename>
struct __copy_move
{
template<typename _II, typename _OI>
@ -330,13 +309,28 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
__copy_m(_II __first, _II __last, _OI __result)
{
for (; __first != __last; ++__result, ++__first)
std::__cm_assign<_IsMove>::__a(__result, __first);
*__result = *__first;
return __result;
}
};
template<bool _IsMove, bool _IsSimple>
struct __copy_move<_IsMove, _IsSimple, random_access_iterator_tag>
#ifdef __GXX_EXPERIMENTAL_CXX0X__
template<typename _Category>
struct __copy_move<true, false, _Category>
{
template<typename _II, typename _OI>
static _OI
__copy_m(_II __first, _II __last, _OI __result)
{
for (; __first != __last; ++__result, ++__first)
*__result = std::move(*__first);
return __result;
}
};
#endif
template<>
struct __copy_move<false, false, random_access_iterator_tag>
{
template<typename _II, typename _OI>
static _OI
@ -345,7 +339,7 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
typedef typename iterator_traits<_II>::difference_type _Distance;
for(_Distance __n = __last - __first; __n > 0; --__n)
{
std::__cm_assign<_IsMove>::__a(__result, __first);
*__result = *__first;
++__first;
++__result;
}
@ -353,6 +347,26 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
}
};
#ifdef __GXX_EXPERIMENTAL_CXX0X__
template<>
struct __copy_move<true, false, random_access_iterator_tag>
{
template<typename _II, typename _OI>
static _OI
__copy_m(_II __first, _II __last, _OI __result)
{
typedef typename iterator_traits<_II>::difference_type _Distance;
for(_Distance __n = __last - __first; __n > 0; --__n)
{
*__result = std::move(*__first);
++__first;
++__result;
}
return __result;
}
};
#endif
template<bool _IsMove>
struct __copy_move<_IsMove, true, random_access_iterator_tag>
{
@ -489,7 +503,7 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
#define _GLIBCXX_MOVE3(_Tp, _Up, _Vp) std::copy(_Tp, _Up, _Vp)
#endif
template<bool _IsMove, bool, typename>
template<bool, bool, typename>
struct __copy_move_backward
{
template<typename _BI1, typename _BI2>
@ -497,13 +511,28 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
__copy_move_b(_BI1 __first, _BI1 __last, _BI2 __result)
{
while (__first != __last)
std::__cm_assign<_IsMove>::__a(--__result, --__last);
*--__result = *--__last;
return __result;
}
};
template<bool _IsMove, bool _IsSimple>
struct __copy_move_backward<_IsMove, _IsSimple, random_access_iterator_tag>
#ifdef __GXX_EXPERIMENTAL_CXX0X__
template<typename _Category>
struct __copy_move_backward<true, false, _Category>
{
template<typename _BI1, typename _BI2>
static _BI2
__copy_move_b(_BI1 __first, _BI1 __last, _BI2 __result)
{
while (__first != __last)
*--__result = std::move(*--__last);
return __result;
}
};
#endif
template<>
struct __copy_move_backward<false, false, random_access_iterator_tag>
{
template<typename _BI1, typename _BI2>
static _BI2
@ -511,11 +540,27 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
{
typename iterator_traits<_BI1>::difference_type __n;
for (__n = __last - __first; __n > 0; --__n)
std::__cm_assign<_IsMove>::__a(--__result, --__last);
*--__result = *--__last;
return __result;
}
};
#ifdef __GXX_EXPERIMENTAL_CXX0X__
template<>
struct __copy_move_backward<true, false, random_access_iterator_tag>
{
template<typename _BI1, typename _BI2>
static _BI2
__copy_move_b(_BI1 __first, _BI1 __last, _BI2 __result)
{
typename iterator_traits<_BI1>::difference_type __n;
for (__n = __last - __first; __n > 0; --__n)
*--__result = std::move(*--__last);
return __result;
}
};
#endif
template<bool _IsMove>
struct __copy_move_backward<_IsMove, true, random_access_iterator_tag>
{

View File

@ -0,0 +1,55 @@
// Copyright (C) 2007 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 2, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without Pred 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 COPYING. If not, write to the Free
// Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
// USA.
// 25.2.1 [lib.alg.copy] Copy.
#include <algorithm>
#include <testsuite_hooks.h>
class Counting_output_iterator
: public std::iterator< std::output_iterator_tag, void, void, void, void >
{
std::size_t c;
public:
Counting_output_iterator() : c(0) {}
Counting_output_iterator& operator++() { return *this; }
Counting_output_iterator& operator*() { return *this; }
template <typename T>
void operator=(const T&) { ++c; }
std::size_t current_counter() const { return c; }
};
// libstdc++/34595
void test01()
{
bool test __attribute__((unused)) = true;
int t[10] = {0,};
Counting_output_iterator cnt;
std::size_t res = std::copy(t+0, t+5, cnt).current_counter();
VERIFY( res == 5 );
}
int main()
{
test01();
return 0;
}