[libcxx-commits] [PATCH] D129823: [libc++][ranges] Make range algorithms support proxy iterators

Konstantin Varlamov via Phabricator via libcxx-commits libcxx-commits at lists.llvm.org
Sun Jul 17 01:27:29 PDT 2022


var-const added inline comments.


================
Comment at: libcxx/include/__algorithm/nth_element.h:76
         {
-            _VSTD::__selection_sort<_Compare>(__first, __last, __comp);
+            std::__selection_sort<_AlgPolicy, _Compare>(__first, __last, __comp);
             return;
----------------
huixie90 wrote:
> question: does this algorithm have the "robust against copy comparator test"? right now the comparator is copied several times but I guess this is fine
Yes, it is verified by the `robust...` test. `_Compare` is either a reference type, or, in debug mode, a small wrapper class that contains a reference member to the actual comparator (this is why `_Compare` is used explicitly to instantiate those functions -- deduction would deduce a non-reference type). Thus in either case, what's being passed around is a reference.


================
Comment at: libcxx/include/__algorithm/pop_heap.h:39
   if (__len > 1) {
     value_type __top = std::move(*__first);  // create a hole at __first
+    _RandomAccessIterator __hole = std::__floyd_sift_down<_AlgPolicy, _CompRef>(__first, __comp_ref, __len);
----------------
huixie90 wrote:
> should this call `iter_move`?
Thanks for catching this, I missed it somehow.


================
Comment at: libcxx/include/__algorithm/sort.h:44
+  using _Comp = _CompT;
+  _Comp& __comp;
+
----------------
huixie90 wrote:
> I am slightly concerned about the reference member because if we are going to copy the comparator around we have risk of having dangling reference. but I guess the trick is that we never copy the comparators?
It's a bit complicated, but there is always a value at the top of the call stack (in `std::sort` or `ranges::sort`), and all the functions down the call stack pass around a reference to the original value. `_WrapAlgPolicy` follows the same approach.


================
Comment at: libcxx/include/__algorithm/sort.h:71
+template <class _Wrapped>
+struct _UnwrapAlgPolicy<_Wrapped, std::enable_if_t<!std::is_same<typename _Wrapped::_AlgPolicy, int>::value>> {
+  using _AlgPolicy = typename _Wrapped::_AlgPolicy;
----------------
huixie90 wrote:
> where does the `int` come from? How can a policy be an `int`?
The expression is meaningless -- I just need to refer to `_Wrapped::_AlgPolicy` in a SFINAE context so that this specialization is preferred when `_Wrapped` is a `_WrapAlgPolicy`.


================
Comment at: libcxx/test/support/test_iterators.h:881-882
 
+  // If `T` is a reference type, the default assignment operator will be deleted.
+  constexpr Proxy& operator=(const Proxy& rhs) {
+    data = rhs.data;
----------------
huixie90 wrote:
> var-const wrote:
> > huixie90 wrote:
> > > hmm.  the two overloads above should already cover this. see the test
> > > https://github.com/llvm/llvm-project/blob/8922adf646eead207fb367dace80bba2abfab2ad/libcxx/test/support/test.support/test_proxy.pass.cpp#L63
> > > 
> > > or did I missing something?
> > I don't want to spend too much time investigating this just because of the deadline coming soon (although it's a pretty interesting issue). The test fails when the assigned type is `const` (which currently isn't tested).
> > 
> > My (unconfirmed) suspicion is that the implicitly-generated default `operator=` is a better match when the type on the right side is `const Proxy&`. Choosing between a template and a non-template function, overload resolution prefers a non-template function if both are an equally good match; `const Proxy&` is an exact match for the signature of the default `operator=`.
> > 
> > Confusingly, however, this works for the move assignment operator, even though the same logic about it being a better match seems to apply. cppreference says that "A deleted implicitly-declared move assignment operator is ignored by overload resolution". Presumably this doesn't apply to a deleted implicitly-declared _copy_ assignment operator, which would explain the difference in behavior.
> > 
> hmm. I suspect the tests are relying on the implicit conversion from T to Proxy<T>. (my original assignment explicitly check if `rhs` is `Proxy` and your new one allows implicit conversions. The class wasn't designed for `Proxy<T> =  T` but if that makes the test easier it would be fine. I will take a look later and it shouldn't block your patch. 
Thanks!


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D129823/new/

https://reviews.llvm.org/D129823



More information about the libcxx-commits mailing list