[range] Optimize erase() in C++11 - use std::move() instead of std::copy() if possible.

This commit is contained in:
Adam Wulkiewicz 2014-06-21 22:08:51 +02:00
parent a0a296877f
commit cd2e17b102
2 changed files with 114 additions and 9 deletions

View File

@ -18,11 +18,13 @@
#include <boost/assert.hpp>
#include <boost/concept_check.hpp>
#include <boost/config.hpp>
#include <boost/range/concepts.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/empty.hpp>
#include <boost/range/size.hpp>
#include <boost/type_traits/is_convertible.hpp>
#include <boost/geometry/core/mutable_range.hpp>
@ -160,6 +162,55 @@ inline void pop_back(Range & rng)
range::resize(rng, boost::size(rng) - 1);
}
namespace detail {
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
template <typename It,
typename OutIt = It,
bool UseMove = boost::is_convertible
<
typename std::iterator_traits<It>::value_type &&,
typename std::iterator_traits<OutIt>::value_type
>::value>
struct copy_or_move_impl
{
static inline OutIt apply(It first, It last, OutIt out)
{
return std::move(first, last, out);
}
};
template <typename It, typename OutIt>
struct copy_or_move_impl<It, OutIt, false>
{
static inline OutIt apply(It first, It last, OutIt out)
{
return std::copy(first, last, out);
}
};
#else
template <typename It, typename OutIt = It, bool /*UseMove*/ = false>
struct copy_or_move_impl
{
static inline OutIt apply(It first, It last, OutIt out)
{
return std::copy(first, last, out);
}
};
#endif
template <typename It, typename OutIt>
inline OutIt copy_or_move(It first, It last, OutIt out)
{
return copy_or_move_impl<It, OutIt>::apply(first, last, out);
}
} // namespace detail
/*!
\brief Short utility to conveniently remove an element from a mutable range.
It uses std::copy() and resize(). Version taking mutable iterators.
@ -177,7 +228,8 @@ erase(Range & rng,
next = it;
++next;
std::copy(next, boost::end(rng), it);
//std::copy(next, boost::end(rng), it);
detail::copy_or_move(next, boost::end(rng), it);
range::resize(rng, boost::size(rng) - 1);
// NOTE: assuming that resize() doesn't invalidate the iterators
@ -225,7 +277,8 @@ erase(Range & rng,
if ( count > 0 )
{
std::copy(last, boost::end(rng), first);
//std::copy(last, boost::end(rng), first);
detail::copy_or_move(last, boost::end(rng), first);
range::resize(rng, boost::size(rng) - count);
}

View File

@ -59,17 +59,44 @@ struct ender<false>
}
};
struct NonMovable
{
NonMovable(int ii = 0) : i(ii) {}
NonMovable(NonMovable const& ii) : i(ii.i) {}
NonMovable & operator=(NonMovable const& ii) { i = ii.i; return *this; }
operator int() { return i; }
int i;
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
private:
NonMovable(NonMovable && ii);
NonMovable & operator=(NonMovable && ii);
#endif
};
struct CopyableAndMovable
{
CopyableAndMovable(int ii = 0) : i(ii) {}
CopyableAndMovable(CopyableAndMovable const& ii) : i(ii.i) {}
CopyableAndMovable & operator=(CopyableAndMovable const& ii) { i = ii.i; return *this; }
operator int() { return i; }
int i;
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
CopyableAndMovable(CopyableAndMovable && ii) : i(std::move(ii.i)) {}
CopyableAndMovable & operator=(CopyableAndMovable && ii) { i = std::move(ii.i); return *this; }
#endif
};
} // namespace bgt
template <bool MutableIterator>
namespace bgr = bg::range;
template <typename T, bool MutableIterator>
void test_all()
{
namespace bgr = bg::range;
bgt::beginner<MutableIterator> begin;
bgt::ender<MutableIterator> end;
std::vector<int> v;
std::vector<T> v;
for (int i = 0 ; i < 20 ; ++i)
{
bgr::push_back(v, i);
@ -92,7 +119,7 @@ void test_all()
BOOST_CHECK(boost::size(v) == 14); // [0,13]
BOOST_CHECK(bgr::back(v) == 13);
std::vector<int>::iterator
typename std::vector<T>::iterator
it = bgr::erase(v, end(v) - 1);
BOOST_CHECK(boost::size(v) == 13); // [0,12]
BOOST_CHECK(bgr::back(v) == 12);
@ -143,10 +170,35 @@ void test_all()
BOOST_CHECK(it == end(v));
}
void test_detail()
{
int arr[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
bgr::detail::copy_or_move(arr + 1, arr + 10, arr);
std::vector<int> v(10, 0);
bgr::detail::copy_or_move(v.begin() + 1, v.begin() + 10, v.begin());
BOOST_CHECK(boost::size(v) == 10);
bgr::erase(v, v.begin() + 1);
BOOST_CHECK(boost::size(v) == 9);
int * arr2[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
bgr::detail::copy_or_move(arr2 + 1, arr2 + 10, arr2);
std::vector<int*> v2(10, 0);
bgr::detail::copy_or_move(v2.begin() + 1, v2.begin() + 10, v2.begin());
BOOST_CHECK(boost::size(v2) == 10);
bgr::erase(v2, v2.begin() + 1);
BOOST_CHECK(boost::size(v2) == 9);
}
int test_main(int, char* [])
{
test_all<true>();
test_all<false>();
test_all<int, true>();
test_all<int, false>();
test_all<bgt::NonMovable, true>();
test_all<bgt::NonMovable, false>();
test_all<bgt::CopyableAndMovable, true>();
test_all<bgt::CopyableAndMovable, false>();
test_detail();
return 0;
}