[llvm] ddbc762 - [ADT] Add deduction guide for iterator_range

Balazs Benics via llvm-commits llvm-commits at lists.llvm.org
Mon Jul 3 00:30:30 PDT 2023


Author: Balazs Benics
Date: 2023-07-03T09:29:37+02:00
New Revision: ddbc7620d46f7bed51abc3eb80f51007e88e2732

URL: https://github.com/llvm/llvm-project/commit/ddbc7620d46f7bed51abc3eb80f51007e88e2732
DIFF: https://github.com/llvm/llvm-project/commit/ddbc7620d46f7bed51abc3eb80f51007e88e2732.diff

LOG: [ADT] Add deduction guide for iterator_range

This commit also enhances the container overload constructor so that it
now considers the `begin` and `end` free functions, and performs ADL
lookups to find the best match.

To make this possible, I had to split-off the ADL helper functions from
the STLExtras header so that the iterator_range still remains pretty
cheap to include.

Differential Revision: https://reviews.llvm.org/D152891

Added: 
    llvm/include/llvm/ADT/ADL.h

Modified: 
    llvm/include/llvm/ADT/STLExtras.h
    llvm/include/llvm/ADT/iterator_range.h

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/ADT/ADL.h b/llvm/include/llvm/ADT/ADL.h
new file mode 100644
index 00000000000000..ab1f28ff6b9c09
--- /dev/null
+++ b/llvm/include/llvm/ADT/ADL.h
@@ -0,0 +1,103 @@
+//===- llvm/ADT/ADL.h - Argument dependent lookup utilities -----*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ADT_ADL_H
+#define LLVM_ADT_ADL_H
+
+#include <type_traits>
+#include <iterator>
+#include <utility>
+
+namespace llvm {
+
+// Only used by compiler if both template types are the same.  Useful when
+// 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));
+}
+
+using std::size;
+
+template <typename RangeT>
+constexpr auto size_impl(RangeT &&range)
+    -> decltype(size(std::forward<RangeT>(range))) {
+  return size(std::forward<RangeT>(range));
+}
+
+} // 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));
+}
+
+/// Returns the size of \p range using `std::size` and functions found through
+/// Argument-Dependent Lookup (ADL).
+template <typename RangeT>
+constexpr auto adl_size(RangeT &&range)
+    -> decltype(adl_detail::size_impl(std::forward<RangeT>(range))) {
+  return adl_detail::size_impl(std::forward<RangeT>(range));
+}
+
+namespace detail {
+
+template <typename RangeT>
+using IterOfRange = decltype(adl_begin(std::declval<RangeT &>()));
+
+template <typename RangeT>
+using ValueOfRange =
+    std::remove_reference_t<decltype(*adl_begin(std::declval<RangeT &>()))>;
+
+} // namespace detail
+} // namespace llvm
+
+#endif // LLVM_ADT_ADL_H

diff  --git a/llvm/include/llvm/ADT/STLExtras.h b/llvm/include/llvm/ADT/STLExtras.h
index 6f4c06bf443309..7edc582636c772 100644
--- a/llvm/include/llvm/ADT/STLExtras.h
+++ b/llvm/include/llvm/ADT/STLExtras.h
@@ -17,6 +17,7 @@
 #ifndef LLVM_ADT_STLEXTRAS_H
 #define LLVM_ADT_STLEXTRAS_H
 
+#include "llvm/ADT/ADL.h"
 #include "llvm/ADT/Hashing.h"
 #include "llvm/ADT/STLForwardCompat.h"
 #include "llvm/ADT/STLFunctionalExtras.h"
@@ -46,90 +47,6 @@
 
 namespace llvm {
 
-// Only used by compiler if both template types are the same.  Useful when
-// 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));
-}
-
-using std::size;
-
-template <typename RangeT>
-constexpr auto size_impl(RangeT &&range)
-    -> decltype(size(std::forward<RangeT>(range))) {
-  return size(std::forward<RangeT>(range));
-}
-
-} // 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));
-}
-
-/// Returns the size of \p range using `std::size` and functions found through
-/// Argument-Dependent Lookup (ADL).
-template <typename RangeT>
-constexpr auto adl_size(RangeT &&range)
-    -> decltype(adl_detail::size_impl(std::forward<RangeT>(range))) {
-  return adl_detail::size_impl(std::forward<RangeT>(range));
-}
-
-namespace detail {
-
-template <typename RangeT>
-using IterOfRange = decltype(adl_begin(std::declval<RangeT &>()));
-
-template <typename RangeT>
-using ValueOfRange =
-    std::remove_reference_t<decltype(*adl_begin(std::declval<RangeT &>()))>;
-
-} // end namespace detail
-
 //===----------------------------------------------------------------------===//
 //     Extra additions to <type_traits>
 //===----------------------------------------------------------------------===//

diff  --git a/llvm/include/llvm/ADT/iterator_range.h b/llvm/include/llvm/ADT/iterator_range.h
index a9b46a3aa45b8b..4f33a27adadd5d 100644
--- a/llvm/include/llvm/ADT/iterator_range.h
+++ b/llvm/include/llvm/ADT/iterator_range.h
@@ -18,10 +18,22 @@
 #ifndef LLVM_ADT_ITERATOR_RANGE_H
 #define LLVM_ADT_ITERATOR_RANGE_H
 
+#include "llvm/ADT/ADL.h"
+#include <type_traits>
 #include <utility>
 
 namespace llvm {
 
+template <typename From, typename To, typename = void>
+struct explicitly_convertable : std::false_type {};
+
+template <typename From, typename To>
+struct explicitly_convertable<
+    From, To,
+    std::void_t<decltype(static_cast<To>(
+        std::declval<std::add_rvalue_reference_t<From>>()))>> : std::true_type {
+};
+
 /// A range adaptor for a pair of iterators.
 ///
 /// This just wraps two iterators into a range-compatible interface. Nothing
@@ -31,12 +43,12 @@ class iterator_range {
   IteratorT begin_iterator, end_iterator;
 
 public:
-  //TODO: Add SFINAE to test that the Container's iterators match the range's
-  //      iterators.
-  template <typename Container>
+  template <typename Container,
+            std::enable_if_t<explicitly_convertable<
+                detail::IterOfRange<Container>, IteratorT>::value> * = nullptr>
   iterator_range(Container &&c)
-  //TODO: Consider ADL/non-member begin/end calls.
-      : begin_iterator(c.begin()), end_iterator(c.end()) {}
+      : begin_iterator(adl_begin(std::forward<Container>(c))),
+        end_iterator(adl_end(std::forward<Container>(c))) {}
   iterator_range(IteratorT begin_iterator, IteratorT end_iterator)
       : begin_iterator(std::move(begin_iterator)),
         end_iterator(std::move(end_iterator)) {}
@@ -46,6 +58,9 @@ class iterator_range {
   bool empty() const { return begin_iterator == end_iterator; }
 };
 
+template <typename Container>
+iterator_range(Container &&) -> iterator_range<detail::IterOfRange<Container>>;
+
 /// Convenience function for iterating over sub-ranges.
 ///
 /// This provides a bit of syntactic sugar to make using sub-ranges


        


More information about the llvm-commits mailing list