[libcxx-commits] [libcxx] 964aeb7 - [libc++][ranges] Make sure all range algorithms support differing projection types:
Konstantin Varlamov via libcxx-commits
libcxx-commits at lists.llvm.org
Tue Jul 26 15:51:58 PDT 2022
Author: Konstantin Varlamov
Date: 2022-07-26T15:51:49-07:00
New Revision: 964aeb713e7be96c2fb9ee06eb6bf47d72de26ca
URL: https://github.com/llvm/llvm-project/commit/964aeb713e7be96c2fb9ee06eb6bf47d72de26ca
DIFF: https://github.com/llvm/llvm-project/commit/964aeb713e7be96c2fb9ee06eb6bf47d72de26ca.diff
LOG: [libc++][ranges] Make sure all range algorithms support differing projection types:
- for all algorithms taking more than one range, add a `robust` test to
check the case where the ranges have different value types and the
given projections are different, with each projection applying to
a different value type;
- fix `ranges::include` to apply the correct projection to each range.
Differential Revision: https://reviews.llvm.org/D130515
Added:
libcxx/test/std/algorithms/ranges_robust_against_differing_projections.pass.cpp
Modified:
libcxx/include/__algorithm/includes.h
libcxx/include/__algorithm/ranges_includes.h
Removed:
################################################################################
diff --git a/libcxx/include/__algorithm/includes.h b/libcxx/include/__algorithm/includes.h
index 102d3db39a2d8..c64194a2c8269 100644
--- a/libcxx/include/__algorithm/includes.h
+++ b/libcxx/include/__algorithm/includes.h
@@ -12,7 +12,10 @@
#include <__algorithm/comp.h>
#include <__algorithm/comp_ref_type.h>
#include <__config>
+#include <__functional/identity.h>
+#include <__functional/invoke.h>
#include <__iterator/iterator_traits.h>
+#include <__type_traits/is_callable.h>
#include <__utility/move.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -21,13 +24,15 @@
_LIBCPP_BEGIN_NAMESPACE_STD
-template <class _Iter1, class _Sent1, class _Iter2, class _Sent2, class _Comp>
+template <class _Iter1, class _Sent1, class _Iter2, class _Sent2, class _Comp, class _Proj1, class _Proj2>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 bool
-__includes(_Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Sent2 __last2, _Comp&& __comp) {
+__includes(_Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Sent2 __last2,
+ _Comp&& __comp, _Proj1&& __proj1, _Proj2&& __proj2) {
for (; __first2 != __last2; ++__first1) {
- if (__first1 == __last1 || __comp(*__first2, *__first1))
+ if (__first1 == __last1 || std::__invoke(
+ __comp, std::__invoke(__proj2, *__first2), std::__invoke(__proj1, *__first1)))
return false;
- if (!__comp(*__first1, *__first2))
+ if (!std::__invoke(__comp, std::__invoke(__proj1, *__first1), std::__invoke(__proj2, *__first2)))
++__first2;
}
return true;
@@ -40,9 +45,13 @@ _LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
_InputIterator2 __first2,
_InputIterator2 __last2,
_Compare __comp) {
+ static_assert(__is_callable<_Compare, decltype(*__first1), decltype(*__first2)>::value,
+ "Comparator has to be callable");
+
typedef typename __comp_ref_type<_Compare>::type _Comp_ref;
return std::__includes(
- std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2), static_cast<_Comp_ref>(__comp));
+ std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2),
+ static_cast<_Comp_ref>(__comp), __identity(), __identity());
}
template <class _InputIterator1, class _InputIterator2>
diff --git a/libcxx/include/__algorithm/ranges_includes.h b/libcxx/include/__algorithm/ranges_includes.h
index ba054e6fd89da..2c7581af68aff 100644
--- a/libcxx/include/__algorithm/ranges_includes.h
+++ b/libcxx/include/__algorithm/ranges_includes.h
@@ -56,7 +56,9 @@ struct __fn {
std::move(__last1),
std::move(__first2),
std::move(__last2),
- ranges::__make_projected_comp(__comp, __proj1, __proj2));
+ std::move(__comp),
+ std::move(__proj1),
+ std::move(__proj2));
}
template <
@@ -73,7 +75,9 @@ struct __fn {
ranges::end(__range1),
ranges::begin(__range2),
ranges::end(__range2),
- ranges::__make_projected_comp(__comp, __proj1, __proj2));
+ std::move(__comp),
+ std::move(__proj1),
+ std::move(__proj2));
}
};
diff --git a/libcxx/test/std/algorithms/ranges_robust_against_
diff ering_projections.pass.cpp b/libcxx/test/std/algorithms/ranges_robust_against_
diff ering_projections.pass.cpp
new file mode 100644
index 0000000000000..b116b78691fda
--- /dev/null
+++ b/libcxx/test/std/algorithms/ranges_robust_against_
diff ering_projections.pass.cpp
@@ -0,0 +1,87 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// <algorithm>
+//
+// Range algorithms should support the case where the ranges they operate on have
diff erent value types and the given
+// projection functors are
diff erent (each projection applies to a
diff erent value type).
+
+#include <algorithm>
+
+#include <array>
+#include <functional>
+#include <iterator>
+#include <ranges>
+#include <utility>
+
+// (in1, in2, ...)
+template <class Func, std::ranges::range Input1, std::ranges::range Input2, class ...Args>
+constexpr void test(Func&& func, Input1& in1, Input2& in2, Args&& ...args) {
+ func(in1.begin(), in1.end(), in2.begin(), in2.end(), std::forward<Args>(args)...);
+ func(in1, in2, std::forward<Args>(args)...);
+}
+
+constexpr bool test_all() {
+ struct A {
+ int x = 0;
+
+ constexpr A() = default;
+ constexpr A(int value) : x(value) {}
+ constexpr operator int() const { return x; }
+
+ constexpr auto operator<=>(const A&) const = default;
+ };
+
+ std::array in = {1, 2, 3};
+ std::array in2 = {A{4}, A{5}, A{6}};
+
+ std::array output = {7, 8, 9, 10, 11, 12};
+ auto out = output.begin();
+ std::array output2 = {A{7}, A{8}, A{9}, A{10}, A{11}, A{12}};
+ auto out2 = output2.begin();
+
+ std::ranges::equal_to eq;
+ std::ranges::less less;
+ auto sum = [](int lhs, A rhs) { return lhs + rhs.x; };
+ auto proj1 = [](int x) { return x * -1; };
+ auto proj2 = [](A a) { return a.x * -1; };
+
+ test(std::ranges::equal, in, in2, eq, proj1, proj2);
+ test(std::ranges::lexicographical_compare, in, in2, eq, proj1, proj2);
+ //test(std::ranges::is_permutation, in, in2, eq, proj1, proj2);
+ test(std::ranges::includes, in, in2, less, proj1, proj2);
+ test(std::ranges::find_first_of, in, in2, eq, proj1, proj2);
+ test(std::ranges::mismatch, in, in2, eq, proj1, proj2);
+ test(std::ranges::search, in, in2, eq, proj1, proj2);
+ test(std::ranges::find_end, in, in2, eq, proj1, proj2);
+ test(std::ranges::transform, in, in2, out, sum, proj1, proj2);
+ test(std::ranges::transform, in, in2, out2, sum, proj1, proj2);
+ //test(std::ranges::partial_sort_copy, in, in2, output2.begin(), output2.end(), less, proj1, proj2);
+ test(std::ranges::merge, in, in2, out, less, proj1, proj2);
+ test(std::ranges::merge, in, in2, out2, less, proj1, proj2);
+ test(std::ranges::set_intersection, in, in2, out, less, proj1, proj2);
+ test(std::ranges::set_intersection, in, in2, out2, less, proj1, proj2);
+ test(std::ranges::set_
diff erence, in, in2, out, less, proj1, proj2);
+ test(std::ranges::set_
diff erence, in, in2, out2, less, proj1, proj2);
+ test(std::ranges::set_symmetric_
diff erence, in, in2, out, less, proj1, proj2);
+ test(std::ranges::set_symmetric_
diff erence, in, in2, out2, less, proj1, proj2);
+ test(std::ranges::set_union, in, in2, out, less, proj1, proj2);
+ test(std::ranges::set_union, in, in2, out2, less, proj1, proj2);
+
+ return true;
+}
+
+int main(int, char**) {
+ test_all();
+ static_assert(test_all());
+
+ return 0;
+}
More information about the libcxx-commits
mailing list