On 05/06/20 22:24 +0200, François Dumont via Libstdc++ wrote:
Hi
ÃÂ ÃÂ ÃÂ Here is the last of my algo patches this time to extend
the memcmp optimization to std::deque iterators and
_GLIBCXX_DEBUG mode.
ÃÂ ÃÂ ÃÂ To do so I had to return int in implementation details of
lexicographical_compare to make sure we can treat a deque
iterator range by chunk in a performant way.
Tested under Linux x86_64 normal and debug modes.
ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ * include/bits/stl_algobase.h
ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ (__lexicographical_compare_impl):
Return int.
ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ (__lexicographical_compare::__lc):
Likewise.
ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ (__lexicographical_compare_aux1(_II1,
_II1, _II2, _II2)): New.
(__lexicographical_compare_aux1(_Deque_iterator<>, _Deque_iterator<>,
ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ _II2, _II2)): Declare.
ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ
(__lexicographical_compare_aux1(_II1, _II1,
ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ _Deque_iterator<>,
_Deque_iterator<>)): Declare.
(__lexicographical_compare_aux1(_Deque_iterator<>, _Deque_iterator<>,
ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ _Deque_iterator<>,
_Deque_iterator<>)): Declare.
ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ (__lexicographical_compare_aux): Adapt,
call later.
Is this meant to say "latter"? That's still not correct grammar
though. I think it would be better to name the function it calls
explicitly: "Call __lexicographical_compare_aux1."
ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ Ã
(__lexicographical_compare_aux(_Safe_iterator<>,
_Safe_iterator<>,
ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ _II2, _II2)): Declare.
ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ
(__lexicographical_compare_aux(_II1, _II1,
ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ _Safe_iterator<>,
_Safe_iterator<>)): Declare.
ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ Ã
(__lexicographical_compare_aux(_Safe_iterator<>,
_Safe_iterator<>,
ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ _Safe_iterator<>,
_Safe_iterator<>)): Declare.
ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ (std::lexicographical_compare): Adapt,
call later without __niter_base
ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ usage.
ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ * include/bits/deque.tcc
(__lex_cmp_dit): New.
ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ (__lexicographical_compare_aux1):
New.
ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ * include/debug/safe_iterator.tcc
ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ (__lexicographical_compare_aux(const
_Safe_iterator<>&,
ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ const _Safe_iterator<>&, _II2,
_II2)): New.
ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ (__lexicographical_compare_aux(
ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ const _Safe_iterator<>&,
const_Safe_iterator<>&,
ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ const _Safe_iterator<>&, const
_Safe_iterator<>&)): New.
ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ *
testsuite/25_algorithms/lexicographical_compare/1.cc (test6,
test7):
ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ New.
ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ *
testsuite/25_algorithms/lexicographical_compare/deque_iterators/1.cc:
ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ New test.
Ok to commit ?
François
diff --git a/libstdc++-v3/include/bits/deque.tcc
b/libstdc++-v3/include/bits/deque.tcc
index 1d32a1691c7..d7dbe64f3e1 100644
--- a/libstdc++-v3/include/bits/deque.tcc
+++ b/libstdc++-v3/include/bits/deque.tcc
@@ -1261,6 +1261,98 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
    return true;
  }
+Â template<typename _Tp, typename _Ref, typename _Ptr, typename _II>
_II is the wrong name here, it mean InputIterator. All callers of this
function are constrained for random access iterators. This cannot be
called with an input iterator. Please use _RAIter.
+Â Â Â int
+Â Â Â __lex_cmp_dit(
+Â Â Â const _GLIBCXX_STD_C::_Deque_iterator<_Tp, _Ref, _Ptr>& __first1,
+Â Â Â const _GLIBCXX_STD_C::_Deque_iterator<_Tp, _Ref, _Ptr>& __last1,
+Â Â Â _II __first2, _II __last2)
+Â Â Â {
+Â Â Â Â Â typedef _GLIBCXX_STD_C::_Deque_iterator<_Tp, _Ref, _Ptr> _Iter;
+Â Â Â Â Â typedef typename _Iter::difference_type difference_type;
+
+Â Â Â Â Â if (__first1._M_node != __last1._M_node)
+Â Â Â {
+Â Â Â Â Â difference_type __len = __last2 - __first2;
+Â Â Â Â Â difference_type __flen
What does "flen" mean? Why not use len2 for last2 - first2, as we do
elsewhere? And then use len for min(len1, len2)?
+Â Â Â Â Â Â Â = std::min(__len, __first1._M_last - __first1._M_cur);
+Â Â Â Â Â if (int __ret = std::__lexicographical_compare_aux1(
This call (and the three later in this function) will do overload
resolution again on the full set of __lexicographical_compare_aux1
overloads, which includes the ones for deque iterators. But we know
that __first1._M_cur and __first1._M_last are not deque iterators.
__first2 could be a deque iterator, but I'm not sure if we really want
one function that has to handle that case anyway.
+Â Â Â Â Â Â Â Â Â __first1._M_cur, __first1._M_last, __first2, __first2
+ __flen))
+Â Â Â Â Â Â Â return __ret;
+
+Â Â Â Â Â __first2 += __flen;
+Â Â Â Â Â __len -= __flen;
+Â Â Â Â Â __flen = std::min<size_t>(__len, _Iter::_S_buffer_size());
+Â Â Â Â Â for (typename _Iter::_Map_pointer __node = __first1._M_node + 1;
+Â Â Â Â Â Â Â Â Â Â __node != __last1._M_node;
+Â Â Â Â Â Â Â Â Â Â __first2 += __flen, __len -= __flen,
+Â Â Â Â Â Â Â Â Â Â __flen = std::min<size_t>(__len, _Iter::_S_buffer_size()),
+Â Â Â Â Â Â Â Â Â Â ++__node)
+Â Â Â Â Â Â Â if (int __ret = std::__lexicographical_compare_aux1(
+Â Â Â Â Â Â Â Â Â *__node, *__node + _Iter::_S_buffer_size(),
+Â Â Â Â Â Â Â Â Â __first2, __first2 + __flen))
+Â Â Â Â Â Â Â Â Â return __ret;
+
+Â Â Â Â Â return std::__lexicographical_compare_aux1(
+Â Â Â Â Â Â Â __last1._M_first, __last1._M_cur, __first2, __last2);
+Â Â Â }
+
+Â Â Â Â Â return std::__lexicographical_compare_aux1(
+Â Â Â Â Â Â Â Â Â __first1._M_cur, __last1._M_cur, __first2, __last2);
+Â Â Â }
+
+Â template<typename _Tp1, typename _Ref1, typename _Ptr1,
+Â Â Â Â Â Â typename _II2>
This is not an input iterator either.
+Â Â Â typename __gnu_cxx::__enable_if<
+Â Â Â Â Â __is_random_access_iter<_II2>::__value, int>::__type
This should be inline.
Also, I'm curious why these overloads use __enable_if rather than the
conventional approach of tag dispatching using iterator_category.
(The same question applies to th __equal_aux1 and __copy_move_a1
overloads for deque iterators as well). It doesn't really matter
though.
+Â Â Â __lexicographical_compare_aux1(
+Â Â Â Â Â Â Â _GLIBCXX_STD_C::_Deque_iterator<_Tp1, _Ref1, _Ptr1> __first1,
+Â Â Â Â Â Â Â _GLIBCXX_STD_C::_Deque_iterator<_Tp1, _Ref1, _Ptr1> __last1,
+Â Â Â Â Â Â Â _II2 __first2, _II2 __last2)
+Â Â Â { return std::__lex_cmp_dit(__first1, __last1, __first2,
__last2); }
+
+Â template<typename _Tp1, typename _Ref1, typename _Ptr1,
+Â Â Â Â Â Â typename _Tp2, typename _Ref2, typename _Ptr2>
+Â Â Â int
This should be inline.
+Â Â Â __lexicographical_compare_aux1(
+Â Â Â Â Â Â Â _GLIBCXX_STD_C::_Deque_iterator<_Tp1, _Ref1, _Ptr1> __first1,
+Â Â Â Â Â Â Â _GLIBCXX_STD_C::_Deque_iterator<_Tp1, _Ref1, _Ptr1> __last1,
+Â Â Â Â Â Â Â _GLIBCXX_STD_C::_Deque_iterator<_Tp2, _Ref2, _Ptr2> __first2,
+Â Â Â Â Â Â Â _GLIBCXX_STD_C::_Deque_iterator<_Tp2, _Ref2, _Ptr2> __last2)
+Â Â Â { return std::__lex_cmp_dit(__first1, __last1, __first2,
__last2); }
I'm not convinced it's useful for this function and the one above it
to share the same logic.
+Â template<typename _II1,
+Â Â Â Â Â Â typename _Tp2, typename _Ref2, typename _Ptr2>
+Â Â Â typename __gnu_cxx::__enable_if<
+Â Â Â Â Â __is_random_access_iter<_II1>::__value, int>::__type
+Â Â Â __lexicographical_compare_aux1(
+Â Â Â Â Â Â Â _II1 __first1, _II1 __last1,
+Â Â Â Â Â Â Â _GLIBCXX_STD_C::_Deque_iterator<_Tp2, _Ref2, _Ptr2> __first2,
+Â Â Â Â Â Â Â _GLIBCXX_STD_C::_Deque_iterator<_Tp2, _Ref2, _Ptr2> __last2)
+Â Â Â {
+Â Â Â Â Â typedef _GLIBCXX_STD_C::_Deque_iterator<_Tp2, _Ref2,
_Ptr2> _Iter;
+Â Â Â Â Â typedef typename _Iter::difference_type difference_type;
+
+Â Â Â Â Â difference_type __len = __last1 - __first1;
+Â Â Â Â Â while (__len > 0)
+Â Â Â {
+Â Â Â Â Â const difference_type __flen = __first2._M_node ==
__last2._M_node
+Â Â Â Â Â Â Â ? __last2._M_cur - __first2._M_cur
+Â Â Â Â Â Â Â : __first2._M_last - __first2._M_cur;
+Â Â Â Â Â const difference_type __clen = std::min(__len, __flen);
"flen"? "clen"?
+Â Â Â Â Â if (int __ret = std::__lexicographical_compare_aux1(
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â __first1, __first1 + __clen,
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â __first2._M_cur, __first2._M_cur + __flen))
+Â Â Â Â Â Â Â return __ret;
+
+Â Â Â Â Â __first1 += __clen;
+Â Â Â Â Â __len -= __clen;
+Â Â Â Â Â __first2 += __clen;
+Â Â Â }
+
+Â Â Â Â Â return __first1 == __last1 ? (__first2 != __last2 ? -1 : 0) : 1;
Isn't this function doing basically the same as __lex_cmp_dit? Why
does it not use the same logic?
Can this whole function just negate the result of __lex_cmp_dit called
with the arguments switched?
 return -std::__lex_cmp_dit(__first2, __last2, __first1, __last1);
That would also fix the bug that makes the following loop forever:
 std::deque<int> d;
 int i = 0;
 std::lexicographical_compare(&i, &i + 1, d.begin(), d.end());