Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/llvm/llvm-project.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHoward Hinnant <hhinnant@apple.com>2012-08-03 22:01:20 +0400
committerHoward Hinnant <hhinnant@apple.com>2012-08-03 22:01:20 +0400
commitaca09de378ff4f5d87de2a75f14f9f9f650553c1 (patch)
tree084075c386aebec9481124d70f47817cfc9b52c6 /libcxx/include/algorithm
parent46342fecd039b8a9c7f14c60ff9896683a53bbf6 (diff)
Performance tweaking rotate.
rotate is a critical algorithm because it is often used by other algorithms, both std and non-std. The main thrust of this optimization is a specialized algorithm when the 'distance' to be shifted is 1 (either left or right). To my surprise, this 'optimization' was not effective for types like std::string. std::string favors rotate algorithms which only use swap. But for types like scalars, and especially when the sequence is random access, these new specializations are a big win. If it is a vector<size_t> for example, the rotate is done via a memmove and can be several times faster than the gcd algorithm. I'm using is_trivially_move_assignable to distinguish between types like int and types like string. This is obviously an ad-hoc approximation, but I haven't found a case where it doesn't give good results. I've used a 'static if' (with is_trivially_move_assignable) in three places. Testing with both -Os and -O3 showed that clang eliminated all code not be executed by the 'static if' (including the 'static if' itself). llvm-svn: 161247
Diffstat (limited to 'libcxx/include/algorithm')
-rw-r--r--libcxx/include/algorithm111
1 files changed, 84 insertions, 27 deletions
diff --git a/libcxx/include/algorithm b/libcxx/include/algorithm
index 67e1101704d9..1ce14b46d425 100644
--- a/libcxx/include/algorithm
+++ b/libcxx/include/algorithm
@@ -2103,12 +2103,31 @@ reverse_copy(_BidirectionalIterator __first, _BidirectionalIterator __last, _Out
template <class _ForwardIterator>
_ForwardIterator
-__rotate(_ForwardIterator __first, _ForwardIterator __middle, _ForwardIterator __last, false_type)
+__rotate_left(_ForwardIterator __first, _ForwardIterator __last)
+{
+ typedef typename iterator_traits<_ForwardIterator>::value_type value_type;
+ value_type __tmp = _VSTD::move(*__first);
+ _ForwardIterator __lm1 = _VSTD::move(_VSTD::next(__first), __last, __first);
+ *__lm1 = _VSTD::move(__tmp);
+ return __lm1;
+}
+
+template <class _BidirectionalIterator>
+_BidirectionalIterator
+__rotate_right(_BidirectionalIterator __first, _BidirectionalIterator __last)
+{
+ typedef typename iterator_traits<_BidirectionalIterator>::value_type value_type;
+ _BidirectionalIterator __lm1 = _VSTD::prev(__last);
+ value_type __tmp = _VSTD::move(*__lm1);
+ _BidirectionalIterator __fp1 = _VSTD::move_backward(__first, __lm1, __last);
+ *__first = _VSTD::move(__tmp);
+ return __fp1;
+}
+
+template <class _ForwardIterator>
+_ForwardIterator
+__rotate_forward(_ForwardIterator __first, _ForwardIterator __middle, _ForwardIterator __last)
{
- if (__first == __middle)
- return __last;
- if (__middle == __last)
- return __first;
_ForwardIterator __i = __middle;
while (true)
{
@@ -2156,15 +2175,11 @@ __gcd(_Integral __x, _Integral __y)
template<typename _RandomAccessIterator>
_RandomAccessIterator
-__rotate(_RandomAccessIterator __first, _RandomAccessIterator __middle, _RandomAccessIterator __last, true_type)
+__rotate_gcd(_RandomAccessIterator __first, _RandomAccessIterator __middle, _RandomAccessIterator __last)
{
typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type;
typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type;
- if (__first == __middle)
- return __last;
- if (__middle == __last)
- return __first;
const difference_type __m1 = __middle - __first;
const difference_type __m2 = __last - __middle;
if (__m1 == __m2)
@@ -2172,15 +2187,15 @@ __rotate(_RandomAccessIterator __first, _RandomAccessIterator __middle, _RandomA
_VSTD::swap_ranges(__first, __middle, __middle);
return __middle;
}
- const difference_type __g = __gcd(__m1, __m2);
+ const difference_type __g = _VSTD::__gcd(__m1, __m2);
for (_RandomAccessIterator __p = __first + __g; __p != __first;)
{
- value_type __t(*--__p);
+ value_type __t(_VSTD::move(*--__p));
_RandomAccessIterator __p1 = __p;
_RandomAccessIterator __p2 = __p1 + __m1;
do
{
- *__p1 = *__p2;
+ *__p1 = _VSTD::move(*__p2);
__p1 = __p2;
const difference_type __d = __last - __p2;
if (__m1 < __d)
@@ -2188,7 +2203,7 @@ __rotate(_RandomAccessIterator __first, _RandomAccessIterator __middle, _RandomA
else
__p2 = __first + (__m1 - __d);
} while (__p2 != __p);
- *__p1 = __t;
+ *__p1 = _VSTD::move(__t);
}
return __first + __m2;
}
@@ -2196,22 +2211,64 @@ __rotate(_RandomAccessIterator __first, _RandomAccessIterator __middle, _RandomA
template <class _ForwardIterator>
inline _LIBCPP_INLINE_VISIBILITY
_ForwardIterator
+__rotate(_ForwardIterator __first, _ForwardIterator __middle, _ForwardIterator __last,
+ _VSTD::forward_iterator_tag)
+{
+ typedef typename _VSTD::iterator_traits<_ForwardIterator>::value_type value_type;
+ if (_VSTD::is_trivially_move_assignable<value_type>::value)
+ {
+ if (_VSTD::next(__first) == __middle)
+ return _VSTD::__rotate_left(__first, __last);
+ }
+ return _VSTD::__rotate_forward(__first, __middle, __last);
+}
+
+template <class _BidirectionalIterator>
+inline _LIBCPP_INLINE_VISIBILITY
+_BidirectionalIterator
+__rotate(_BidirectionalIterator __first, _BidirectionalIterator __middle, _BidirectionalIterator __last,
+ _VSTD::bidirectional_iterator_tag)
+{
+ typedef typename _VSTD::iterator_traits<_BidirectionalIterator>::value_type value_type;
+ if (_VSTD::is_trivially_move_assignable<value_type>::value)
+ {
+ if (_VSTD::next(__first) == __middle)
+ return _VSTD::__rotate_left(__first, __last);
+ if (_VSTD::next(__middle) == __last)
+ return _VSTD::__rotate_right(__first, __last);
+ }
+ return _VSTD::__rotate_forward(__first, __middle, __last);
+}
+
+template <class _RandomAccessIterator>
+inline _LIBCPP_INLINE_VISIBILITY
+_RandomAccessIterator
+__rotate(_RandomAccessIterator __first, _RandomAccessIterator __middle, _RandomAccessIterator __last,
+ _VSTD::random_access_iterator_tag)
+{
+ typedef typename _VSTD::iterator_traits<_RandomAccessIterator>::value_type value_type;
+ if (_VSTD::is_trivially_move_assignable<value_type>::value)
+ {
+ if (_VSTD::next(__first) == __middle)
+ return _VSTD::__rotate_left(__first, __last);
+ if (_VSTD::next(__middle) == __last)
+ return _VSTD::__rotate_right(__first, __last);
+ return _VSTD::__rotate_gcd(__first, __middle, __last);
+ }
+ return _VSTD::__rotate_forward(__first, __middle, __last);
+}
+
+template <class _ForwardIterator>
+inline _LIBCPP_INLINE_VISIBILITY
+_ForwardIterator
rotate(_ForwardIterator __first, _ForwardIterator __middle, _ForwardIterator __last)
{
+ if (__first == __middle)
+ return __last;
+ if (__middle == __last)
+ return __first;
return _VSTD::__rotate(__first, __middle, __last,
- integral_constant
- <
- bool,
- is_convertible
- <
- typename iterator_traits<_ForwardIterator>::iterator_category,
- random_access_iterator_tag
- >::value &&
- is_trivially_copy_assignable
- <
- typename iterator_traits<_ForwardIterator>::value_type
- >::value
- >());
+ typename _VSTD::iterator_traits<_ForwardIterator>::iterator_category());
}
// rotate_copy