[llvm] da0d816 - [ADT] Fix definition of `adl_begin`/`adl_end` and `Iter`/`ValueOfRange`
Jakub Kuderski via llvm-commits
llvm-commits at lists.llvm.org
Mon Feb 27 17:31:34 PST 2023
Author: Jakub Kuderski
Date: 2023-02-27T20:31:09-05:00
New Revision: da0d816567e229da01b5663e8587114d469e2b0b
URL: https://github.com/llvm/llvm-project/commit/da0d816567e229da01b5663e8587114d469e2b0b
DIFF: https://github.com/llvm/llvm-project/commit/da0d816567e229da01b5663e8587114d469e2b0b.diff
LOG: [ADT] Fix definition of `adl_begin`/`adl_end` and `Iter`/`ValueOfRange`
- Make `IterOfRange` and `ValueOfRange` work with types that require
custom `begin`/`end` functions.
- Allow for `adl_begin`/`adl_end` to be used in constant-evaluated
contexts.
- Use SFINAE-friendly trailing return type deductions `adl_begin`/`adl_end` so that they are useable in template argument deduction.
- Add missing documentation comments.
This is required for future work in https://reviews.llvm.org/D144503.
Reviewed By: dblaikie, zero9178
Differential Revision: https://reviews.llvm.org/D144583
Added:
Modified:
llvm/include/llvm/ADT/STLExtras.h
llvm/unittests/ADT/STLExtrasTest.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/ADT/STLExtras.h b/llvm/include/llvm/ADT/STLExtras.h
index 8702024d73d5b..f1a6587ecc7f3 100644
--- a/llvm/include/llvm/ADT/STLExtras.h
+++ b/llvm/include/llvm/ADT/STLExtras.h
@@ -50,14 +50,67 @@ namespace llvm {
// using SFINAE to test for the existence of member functions.
template <typename T, T> struct SameType;
+namespace adl_detail {
+
+using std::begin;
+
+template <typename RangeT>
+constexpr auto begin_impl(RangeT &&range)
+ -> decltype(begin(std::forward<RangeT>(range))) {
+ return begin(std::forward<RangeT>(range));
+}
+
+using std::end;
+
+template <typename RangeT>
+constexpr auto end_impl(RangeT &&range)
+ -> decltype(end(std::forward<RangeT>(range))) {
+ return end(std::forward<RangeT>(range));
+}
+
+using std::swap;
+
+template <typename T>
+constexpr void swap_impl(T &&lhs,
+ T &&rhs) noexcept(noexcept(swap(std::declval<T>(),
+ std::declval<T>()))) {
+ swap(std::forward<T>(lhs), std::forward<T>(rhs));
+}
+
+} // end namespace adl_detail
+
+/// Returns the begin iterator to \p range using `std::begin` and
+/// function found through Argument-Dependent Lookup (ADL).
+template <typename RangeT>
+constexpr auto adl_begin(RangeT &&range)
+ -> decltype(adl_detail::begin_impl(std::forward<RangeT>(range))) {
+ return adl_detail::begin_impl(std::forward<RangeT>(range));
+}
+
+/// Returns the end iterator to \p range using `std::end` and
+/// functions found through Argument-Dependent Lookup (ADL).
+template <typename RangeT>
+constexpr auto adl_end(RangeT &&range)
+ -> decltype(adl_detail::end_impl(std::forward<RangeT>(range))) {
+ return adl_detail::end_impl(std::forward<RangeT>(range));
+}
+
+/// Swaps \p lhs with \p rhs using `std::swap` and functions found through
+/// Argument-Dependent Lookup (ADL).
+template <typename T>
+constexpr void adl_swap(T &&lhs, T &&rhs) noexcept(
+ noexcept(adl_detail::swap_impl(std::declval<T>(), std::declval<T>()))) {
+ adl_detail::swap_impl(std::forward<T>(lhs), std::forward<T>(rhs));
+}
+
namespace detail {
template <typename RangeT>
-using IterOfRange = decltype(std::begin(std::declval<RangeT &>()));
+using IterOfRange = decltype(adl_begin(std::declval<RangeT &>()));
template <typename RangeT>
using ValueOfRange =
- std::remove_reference_t<decltype(*std::begin(std::declval<RangeT &>()))>;
+ std::remove_reference_t<decltype(*adl_begin(std::declval<RangeT &>()))>;
} // end namespace detail
@@ -333,48 +386,6 @@ template <typename T> class Callable<T, true> {
} // namespace callable_detail
-namespace adl_detail {
-
-using std::begin;
-
-template <typename ContainerTy>
-decltype(auto) adl_begin(ContainerTy &&container) {
- return begin(std::forward<ContainerTy>(container));
-}
-
-using std::end;
-
-template <typename ContainerTy>
-decltype(auto) adl_end(ContainerTy &&container) {
- return end(std::forward<ContainerTy>(container));
-}
-
-using std::swap;
-
-template <typename T>
-void adl_swap(T &&lhs, T &&rhs) noexcept(noexcept(swap(std::declval<T>(),
- std::declval<T>()))) {
- swap(std::forward<T>(lhs), std::forward<T>(rhs));
-}
-
-} // end namespace adl_detail
-
-template <typename ContainerTy>
-decltype(auto) adl_begin(ContainerTy &&container) {
- return adl_detail::adl_begin(std::forward<ContainerTy>(container));
-}
-
-template <typename ContainerTy>
-decltype(auto) adl_end(ContainerTy &&container) {
- return adl_detail::adl_end(std::forward<ContainerTy>(container));
-}
-
-template <typename T>
-void adl_swap(T &&lhs, T &&rhs) noexcept(
- noexcept(adl_detail::adl_swap(std::declval<T>(), std::declval<T>()))) {
- adl_detail::adl_swap(std::forward<T>(lhs), std::forward<T>(rhs));
-}
-
/// Returns true if the given container only contains a single element.
template <typename ContainerTy> bool hasSingleElement(ContainerTy &&C) {
auto B = std::begin(C), E = std::end(C);
diff --git a/llvm/unittests/ADT/STLExtrasTest.cpp b/llvm/unittests/ADT/STLExtrasTest.cpp
index 948cbaed16c08..a1636237b4eeb 100644
--- a/llvm/unittests/ADT/STLExtrasTest.cpp
+++ b/llvm/unittests/ADT/STLExtrasTest.cpp
@@ -12,6 +12,7 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"
+#include <array>
#include <climits>
#include <list>
#include <vector>
@@ -394,6 +395,10 @@ void swap(some_struct &lhs, some_struct &rhs) {
lhs.swap_val = "lhs";
rhs.swap_val = "rhs";
}
+
+struct requires_move {};
+int *begin(requires_move &&) { return nullptr; }
+int *end(requires_move &&) { return nullptr; }
} // namespace some_namespace
TEST(STLExtrasTest, ADLTest) {
@@ -409,7 +414,25 @@ TEST(STLExtrasTest, ADLTest) {
int count = 0;
llvm::for_each(s, [&count](int) { ++count; });
- EXPECT_EQ(5, count);
+ EXPECT_EQ(count, 5);
+}
+
+TEST(STLExtrasTest, ADLTestTemporaryRange) {
+ EXPECT_EQ(adl_begin(some_namespace::requires_move{}), nullptr);
+ EXPECT_EQ(adl_end(some_namespace::requires_move{}), nullptr);
+}
+
+TEST(STLExtrasTest, ADLTestConstexpr) {
+ // `std::begin`/`std::end` are marked as `constexpr`; check that
+ // `adl_begin`/`adl_end` also work in constant-evaluated contexts.
+ static constexpr int c_arr[] = {7, 8, 9};
+ static_assert(adl_begin(c_arr) == c_arr);
+ static_assert(adl_end(c_arr) == c_arr + 3);
+
+ static constexpr std::array<int, 2> std_arr = {1, 2};
+ static_assert(adl_begin(std_arr) == std_arr.begin());
+ static_assert(adl_end(std_arr) == std_arr.end());
+ SUCCEED();
}
TEST(STLExtrasTest, DropBeginTest) {
More information about the llvm-commits
mailing list