[libcxx-commits] [libcxx] [libc++] Added segmented iterator for std::equal (PR #106254)

via libcxx-commits libcxx-commits at lists.llvm.org
Tue Aug 27 23:44:57 PDT 2024


https://github.com/NoumanAmir657 updated https://github.com/llvm/llvm-project/pull/106254

>From 69b32e82068d33c2403739710f66751351383750 Mon Sep 17 00:00:00 2001
From: nouman-10x <noumanamir453 at gmail.com>
Date: Tue, 27 Aug 2024 22:27:37 +0500
Subject: [PATCH 1/5] Added segmented iterator for equal

---
 libcxx/include/__algorithm/equal.h | 134 +++++++++++++++++++++++++++++
 1 file changed, 134 insertions(+)

diff --git a/libcxx/include/__algorithm/equal.h b/libcxx/include/__algorithm/equal.h
index bfc8f72f6eb195..c7d8eb54026bba 100644
--- a/libcxx/include/__algorithm/equal.h
+++ b/libcxx/include/__algorithm/equal.h
@@ -24,6 +24,7 @@
 #include <__type_traits/is_equality_comparable.h>
 #include <__type_traits/is_volatile.h>
 #include <__utility/move.h>
+#include <__iterator/segmented_iterator.h>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -54,9 +55,68 @@ __equal_iter_impl(_Tp* __first1, _Tp* __last1, _Up* __first2, _BinaryPredicate&)
   return std::__constexpr_memcmp_equal(__first1, __first2, __element_count(__last1 - __first1));
 }
 
+template <class _SegmentedIterator1, class _SegmentedIterator2, class _BinaryPredicate>
+_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool
+__equal_segment_iter(_SegmentedIterator1 __first1, _SegmentedIterator1 __last1, _SegmentedIterator2 __first2, _BinaryPredicate __pred) {
+  using _Traits1 = __segmented_iterator_traits<_SegmentedIterator1>;
+  using _Traits2 = __segmented_iterator_traits<_SegmentedIterator2>;
+
+  auto __sfirst1 = _Traits1::__segment(__first1);
+  auto __slast1  = _Traits1::__segment(__last1);
+
+  auto __sfirst2 = _Traits2::__segment(__first2);
+
+  // Both have only 1 segment
+  if (__sfirst1 == __slast1)
+    return std::__equal_iter_impl(
+      std::__unwrap_iter(_Traits1::__local(__first1)),
+      std::__unwrap_iter(_Traits1::__local(__last1)),
+      std::__unwrap_iter(_Traits2::__local(__first2)),
+      __pred);
+
+  { // We have more than one segment. Iterate over the first segment, since we might not start at the beginning
+    if (!std::__equal_iter_impl(
+      std::__unwrap_iter(_Traits1::__local(__first1)),
+      std::__unwrap_iter(_Traits1::__end(__sfirst1)),
+      std::__unwrap_iter(_Traits2::__local(__first2)),
+      __pred)) {
+        return false;
+    }
+  }
+  ++__sfirst1;
+  ++__sfirst2;
+
+  // Iterate over the segments which are guaranteed to be completely in the range
+  while (__sfirst1 != __slast1) {
+    if (!std::__equal_iter_impl(
+      std::__unwrap_iter(_Traits1::__begin(__sfirst1)),
+      std::__unwrap_iter(_Traits1::__end(__sfirst1)),
+      std::__unwrap_iter(_Traits2::__begin(__sfirst2)),
+      __pred)) {
+        return false;
+      }
+    ++__sfirst1;
+    ++__sfirst2;
+  }
+
+  // Iterate over the last segment
+  if (!std::__equal_iter_impl(
+    std::__unwrap_iter(_Traits1::__begin(__sfirst1)),
+    std::__unwrap_iter(_Traits1::__local(__last1)),
+    std::__unwrap_iter(_Traits2::__begin(__sfirst2)),
+    __pred)) {
+      return false;
+  }
+
+  return true;
+}
+
 template <class _InputIterator1, class _InputIterator2, class _BinaryPredicate>
 _LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool
 equal(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _BinaryPredicate __pred) {
+  if constexpr (__is_segmented_iterator<_InputIterator1>::value && __is_segmented_iterator<_InputIterator2>::value) {
+    return std::__equal_segment_iter(__first1, __last1, __first2, __pred);
+  }
   return std::__equal_iter_impl(
       std::__unwrap_iter(__first1), std::__unwrap_iter(__last1), std::__unwrap_iter(__first2), __pred);
 }
@@ -95,6 +155,75 @@ __equal_impl(_Tp* __first1, _Tp* __last1, _Up* __first2, _Up*, _Pred&, _Proj1&,
   return std::__constexpr_memcmp_equal(__first1, __first2, __element_count(__last1 - __first1));
 }
 
+template <class _SegmentedIterator1, class _SegmentedIterator2, class _BinaryPredicate, class _Proj1, class _Proj2>
+_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool
+__equal_segment(_SegmentedIterator1 __first1, _SegmentedIterator1 __last1, _SegmentedIterator2 __first2, _SegmentedIterator2 __last2, _BinaryPredicate __pred, _Proj1& __proj1, _Proj2& __proj2) {
+  using _Traits1 = __segmented_iterator_traits<_SegmentedIterator1>;
+  using _Traits2 = __segmented_iterator_traits<_SegmentedIterator2>;
+
+  auto __sfirst1 = _Traits1::__segment(__first1);
+  auto __slast1  = _Traits1::__segment(__last1);
+
+  auto __sfirst2 = _Traits2::__segment(__first2);
+  auto __slast2  = _Traits2::__segment(__last2);
+
+  // Both have only 1 segment
+  if (__sfirst1 == __slast1 && __sfirst2 == __slast2)
+    return std::__equal_impl(
+      std::__unwrap_iter(_Traits1::__local(__first1)),
+      std::__unwrap_iter(_Traits1::__local(__last1)),
+      std::__unwrap_iter(_Traits2::__local(__first2)),
+      std::__unwrap_iter(_Traits2::__local(__last2)),
+      __pred,
+      __proj1,
+      __proj2);
+
+  { // We have more than one segment. Iterate over the first segment, since we might not start at the beginning
+    if (!std::__equal_impl(
+      std::__unwrap_iter(_Traits1::__local(__first1)),
+      std::__unwrap_iter(_Traits1::__end(__sfirst1)),
+      std::__unwrap_iter(_Traits2::__local(__first2)),
+      std::__unwrap_iter(_Traits2::__end(__sfirst2)),
+      __pred,
+      __proj1,
+      __proj2)) {
+        return false;
+      }
+  }
+  ++__sfirst1;
+  ++__sfirst2;
+
+  // Iterate over the segments which are guaranteed to be completely in the range
+  while (__sfirst1 != __slast1 && __sfirst2 != __slast2) {
+    if (!std::__equal_impl(
+      std::__unwrap_iter(_Traits1::__begin(__sfirst1)),
+      std::__unwrap_iter(_Traits1::__end(__sfirst1)),
+      std::__unwrap_iter(_Traits2::__begin(__sfirst2)),
+      std::__unwrap_iter(_Traits2::__end(__sfirst2)),
+      __pred,
+      __proj1,
+      __proj2)) {
+        return false;
+      }
+    ++__sfirst1;
+    ++__sfirst2;
+  }
+
+  // Iterate over the last segment
+  if (!std::__equal_impl(
+    std::__unwrap_iter(_Traits1::__begin(__sfirst1)),
+    std::__unwrap_iter(_Traits1::__local(__last1)),
+    std::__unwrap_iter(_Traits2::__begin(__sfirst2)),
+    std::__unwrap_iter(_Traits2::__local(__last2)),
+    __pred,
+    __proj1,
+    __proj2)) {
+      return false;
+  }
+
+  return __sfirst1 == __slast1 && __sfirst2 == __slast2;
+}
+
 template <class _InputIterator1, class _InputIterator2, class _BinaryPredicate>
 _LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool
 equal(_InputIterator1 __first1,
@@ -108,6 +237,11 @@ equal(_InputIterator1 __first1,
       return false;
   }
   __identity __proj;
+
+  if constexpr (__is_segmented_iterator<_InputIterator1>::value && __is_segmented_iterator<_InputIterator2>::value) {
+    return std::__equal_segment(__first1, __last1, __first2, __last2, __pred, __proj, __proj);
+  }
+
   return std::__equal_impl(
       std::__unwrap_iter(__first1),
       std::__unwrap_iter(__last1),

>From 04eb22342be699ecc198cf40e4a891eda9dfe319 Mon Sep 17 00:00:00 2001
From: nouman-10x <noumanamir453 at gmail.com>
Date: Tue, 27 Aug 2024 22:33:33 +0500
Subject: [PATCH 2/5] Formatted

---
 libcxx/include/__algorithm/equal.h | 122 +++++++++++++++--------------
 1 file changed, 64 insertions(+), 58 deletions(-)

diff --git a/libcxx/include/__algorithm/equal.h b/libcxx/include/__algorithm/equal.h
index c7d8eb54026bba..3de7f170953732 100644
--- a/libcxx/include/__algorithm/equal.h
+++ b/libcxx/include/__algorithm/equal.h
@@ -17,6 +17,7 @@
 #include <__functional/invoke.h>
 #include <__iterator/distance.h>
 #include <__iterator/iterator_traits.h>
+#include <__iterator/segmented_iterator.h>
 #include <__string/constexpr_c_functions.h>
 #include <__type_traits/desugars_to.h>
 #include <__type_traits/enable_if.h>
@@ -24,7 +25,6 @@
 #include <__type_traits/is_equality_comparable.h>
 #include <__type_traits/is_volatile.h>
 #include <__utility/move.h>
-#include <__iterator/segmented_iterator.h>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -56,8 +56,8 @@ __equal_iter_impl(_Tp* __first1, _Tp* __last1, _Up* __first2, _BinaryPredicate&)
 }
 
 template <class _SegmentedIterator1, class _SegmentedIterator2, class _BinaryPredicate>
-_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool
-__equal_segment_iter(_SegmentedIterator1 __first1, _SegmentedIterator1 __last1, _SegmentedIterator2 __first2, _BinaryPredicate __pred) {
+_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __equal_segment_iter(
+    _SegmentedIterator1 __first1, _SegmentedIterator1 __last1, _SegmentedIterator2 __first2, _BinaryPredicate __pred) {
   using _Traits1 = __segmented_iterator_traits<_SegmentedIterator1>;
   using _Traits2 = __segmented_iterator_traits<_SegmentedIterator2>;
 
@@ -69,18 +69,18 @@ __equal_segment_iter(_SegmentedIterator1 __first1, _SegmentedIterator1 __last1,
   // Both have only 1 segment
   if (__sfirst1 == __slast1)
     return std::__equal_iter_impl(
-      std::__unwrap_iter(_Traits1::__local(__first1)),
-      std::__unwrap_iter(_Traits1::__local(__last1)),
-      std::__unwrap_iter(_Traits2::__local(__first2)),
-      __pred);
+        std::__unwrap_iter(_Traits1::__local(__first1)),
+        std::__unwrap_iter(_Traits1::__local(__last1)),
+        std::__unwrap_iter(_Traits2::__local(__first2)),
+        __pred);
 
   { // We have more than one segment. Iterate over the first segment, since we might not start at the beginning
     if (!std::__equal_iter_impl(
-      std::__unwrap_iter(_Traits1::__local(__first1)),
-      std::__unwrap_iter(_Traits1::__end(__sfirst1)),
-      std::__unwrap_iter(_Traits2::__local(__first2)),
-      __pred)) {
-        return false;
+            std::__unwrap_iter(_Traits1::__local(__first1)),
+            std::__unwrap_iter(_Traits1::__end(__sfirst1)),
+            std::__unwrap_iter(_Traits2::__local(__first2)),
+            __pred)) {
+      return false;
     }
   }
   ++__sfirst1;
@@ -89,23 +89,23 @@ __equal_segment_iter(_SegmentedIterator1 __first1, _SegmentedIterator1 __last1,
   // Iterate over the segments which are guaranteed to be completely in the range
   while (__sfirst1 != __slast1) {
     if (!std::__equal_iter_impl(
-      std::__unwrap_iter(_Traits1::__begin(__sfirst1)),
-      std::__unwrap_iter(_Traits1::__end(__sfirst1)),
-      std::__unwrap_iter(_Traits2::__begin(__sfirst2)),
-      __pred)) {
-        return false;
-      }
+            std::__unwrap_iter(_Traits1::__begin(__sfirst1)),
+            std::__unwrap_iter(_Traits1::__end(__sfirst1)),
+            std::__unwrap_iter(_Traits2::__begin(__sfirst2)),
+            __pred)) {
+      return false;
+    }
     ++__sfirst1;
     ++__sfirst2;
   }
 
   // Iterate over the last segment
   if (!std::__equal_iter_impl(
-    std::__unwrap_iter(_Traits1::__begin(__sfirst1)),
-    std::__unwrap_iter(_Traits1::__local(__last1)),
-    std::__unwrap_iter(_Traits2::__begin(__sfirst2)),
-    __pred)) {
-      return false;
+          std::__unwrap_iter(_Traits1::__begin(__sfirst1)),
+          std::__unwrap_iter(_Traits1::__local(__last1)),
+          std::__unwrap_iter(_Traits2::__begin(__sfirst2)),
+          __pred)) {
+    return false;
   }
 
   return true;
@@ -156,8 +156,14 @@ __equal_impl(_Tp* __first1, _Tp* __last1, _Up* __first2, _Up*, _Pred&, _Proj1&,
 }
 
 template <class _SegmentedIterator1, class _SegmentedIterator2, class _BinaryPredicate, class _Proj1, class _Proj2>
-_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool
-__equal_segment(_SegmentedIterator1 __first1, _SegmentedIterator1 __last1, _SegmentedIterator2 __first2, _SegmentedIterator2 __last2, _BinaryPredicate __pred, _Proj1& __proj1, _Proj2& __proj2) {
+_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __equal_segment(
+    _SegmentedIterator1 __first1,
+    _SegmentedIterator1 __last1,
+    _SegmentedIterator2 __first2,
+    _SegmentedIterator2 __last2,
+    _BinaryPredicate __pred,
+    _Proj1& __proj1,
+    _Proj2& __proj2) {
   using _Traits1 = __segmented_iterator_traits<_SegmentedIterator1>;
   using _Traits2 = __segmented_iterator_traits<_SegmentedIterator2>;
 
@@ -170,25 +176,25 @@ __equal_segment(_SegmentedIterator1 __first1, _SegmentedIterator1 __last1, _Segm
   // Both have only 1 segment
   if (__sfirst1 == __slast1 && __sfirst2 == __slast2)
     return std::__equal_impl(
-      std::__unwrap_iter(_Traits1::__local(__first1)),
-      std::__unwrap_iter(_Traits1::__local(__last1)),
-      std::__unwrap_iter(_Traits2::__local(__first2)),
-      std::__unwrap_iter(_Traits2::__local(__last2)),
-      __pred,
-      __proj1,
-      __proj2);
+        std::__unwrap_iter(_Traits1::__local(__first1)),
+        std::__unwrap_iter(_Traits1::__local(__last1)),
+        std::__unwrap_iter(_Traits2::__local(__first2)),
+        std::__unwrap_iter(_Traits2::__local(__last2)),
+        __pred,
+        __proj1,
+        __proj2);
 
   { // We have more than one segment. Iterate over the first segment, since we might not start at the beginning
     if (!std::__equal_impl(
-      std::__unwrap_iter(_Traits1::__local(__first1)),
-      std::__unwrap_iter(_Traits1::__end(__sfirst1)),
-      std::__unwrap_iter(_Traits2::__local(__first2)),
-      std::__unwrap_iter(_Traits2::__end(__sfirst2)),
-      __pred,
-      __proj1,
-      __proj2)) {
-        return false;
-      }
+            std::__unwrap_iter(_Traits1::__local(__first1)),
+            std::__unwrap_iter(_Traits1::__end(__sfirst1)),
+            std::__unwrap_iter(_Traits2::__local(__first2)),
+            std::__unwrap_iter(_Traits2::__end(__sfirst2)),
+            __pred,
+            __proj1,
+            __proj2)) {
+      return false;
+    }
   }
   ++__sfirst1;
   ++__sfirst2;
@@ -196,29 +202,29 @@ __equal_segment(_SegmentedIterator1 __first1, _SegmentedIterator1 __last1, _Segm
   // Iterate over the segments which are guaranteed to be completely in the range
   while (__sfirst1 != __slast1 && __sfirst2 != __slast2) {
     if (!std::__equal_impl(
-      std::__unwrap_iter(_Traits1::__begin(__sfirst1)),
-      std::__unwrap_iter(_Traits1::__end(__sfirst1)),
-      std::__unwrap_iter(_Traits2::__begin(__sfirst2)),
-      std::__unwrap_iter(_Traits2::__end(__sfirst2)),
-      __pred,
-      __proj1,
-      __proj2)) {
-        return false;
-      }
+            std::__unwrap_iter(_Traits1::__begin(__sfirst1)),
+            std::__unwrap_iter(_Traits1::__end(__sfirst1)),
+            std::__unwrap_iter(_Traits2::__begin(__sfirst2)),
+            std::__unwrap_iter(_Traits2::__end(__sfirst2)),
+            __pred,
+            __proj1,
+            __proj2)) {
+      return false;
+    }
     ++__sfirst1;
     ++__sfirst2;
   }
 
   // Iterate over the last segment
   if (!std::__equal_impl(
-    std::__unwrap_iter(_Traits1::__begin(__sfirst1)),
-    std::__unwrap_iter(_Traits1::__local(__last1)),
-    std::__unwrap_iter(_Traits2::__begin(__sfirst2)),
-    std::__unwrap_iter(_Traits2::__local(__last2)),
-    __pred,
-    __proj1,
-    __proj2)) {
-      return false;
+          std::__unwrap_iter(_Traits1::__begin(__sfirst1)),
+          std::__unwrap_iter(_Traits1::__local(__last1)),
+          std::__unwrap_iter(_Traits2::__begin(__sfirst2)),
+          std::__unwrap_iter(_Traits2::__local(__last2)),
+          __pred,
+          __proj1,
+          __proj2)) {
+    return false;
   }
 
   return __sfirst1 == __slast1 && __sfirst2 == __slast2;

>From 2461ca61eb395630c7964ceb290da1ba771f3c8c Mon Sep 17 00:00:00 2001
From: nouman-10x <noumanamir453 at gmail.com>
Date: Tue, 27 Aug 2024 23:07:55 +0500
Subject: [PATCH 3/5] Removes constexpr and fixed clang-tidy warnings

---
 libcxx/include/__algorithm/equal.h | 16 ++++++----------
 1 file changed, 6 insertions(+), 10 deletions(-)

diff --git a/libcxx/include/__algorithm/equal.h b/libcxx/include/__algorithm/equal.h
index 3de7f170953732..d21a1211958d42 100644
--- a/libcxx/include/__algorithm/equal.h
+++ b/libcxx/include/__algorithm/equal.h
@@ -100,21 +100,17 @@ _LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 boo
   }
 
   // Iterate over the last segment
-  if (!std::__equal_iter_impl(
-          std::__unwrap_iter(_Traits1::__begin(__sfirst1)),
-          std::__unwrap_iter(_Traits1::__local(__last1)),
-          std::__unwrap_iter(_Traits2::__begin(__sfirst2)),
-          __pred)) {
-    return false;
-  }
-
-  return true;
+  return std::__equal_iter_impl(
+      std::__unwrap_iter(_Traits1::__begin(__sfirst1)),
+      std::__unwrap_iter(_Traits1::__local(__last1)),
+      std::__unwrap_iter(_Traits2::__begin(__sfirst2)),
+      __pred)
 }
 
 template <class _InputIterator1, class _InputIterator2, class _BinaryPredicate>
 _LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool
 equal(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _BinaryPredicate __pred) {
-  if constexpr (__is_segmented_iterator<_InputIterator1>::value && __is_segmented_iterator<_InputIterator2>::value) {
+  if (__is_segmented_iterator<_InputIterator1>::value && __is_segmented_iterator<_InputIterator2>::value) {
     return std::__equal_segment_iter(__first1, __last1, __first2, __pred);
   }
   return std::__equal_iter_impl(

>From 7c9d665aed83089c9336f3ad0654e4e9c815dd6a Mon Sep 17 00:00:00 2001
From: nouman-10x <noumanamir453 at gmail.com>
Date: Tue, 27 Aug 2024 23:16:11 +0500
Subject: [PATCH 4/5] Semicolon ...

---
 libcxx/include/__algorithm/equal.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/include/__algorithm/equal.h b/libcxx/include/__algorithm/equal.h
index d21a1211958d42..18f4224708cc9f 100644
--- a/libcxx/include/__algorithm/equal.h
+++ b/libcxx/include/__algorithm/equal.h
@@ -104,7 +104,7 @@ _LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 boo
       std::__unwrap_iter(_Traits1::__begin(__sfirst1)),
       std::__unwrap_iter(_Traits1::__local(__last1)),
       std::__unwrap_iter(_Traits2::__begin(__sfirst2)),
-      __pred)
+      __pred);
 }
 
 template <class _InputIterator1, class _InputIterator2, class _BinaryPredicate>

>From 3462957b6483ef5d27ffc4b1bf805b92a5c0936c Mon Sep 17 00:00:00 2001
From: nouman-10x <noumanamir453 at gmail.com>
Date: Wed, 28 Aug 2024 11:44:23 +0500
Subject: [PATCH 5/5] Test

---
 libcxx/include/__algorithm/equal.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/include/__algorithm/equal.h b/libcxx/include/__algorithm/equal.h
index 18f4224708cc9f..9c83e55ac67f34 100644
--- a/libcxx/include/__algorithm/equal.h
+++ b/libcxx/include/__algorithm/equal.h
@@ -10,6 +10,7 @@
 #ifndef _LIBCPP___ALGORITHM_EQUAL_H
 #define _LIBCPP___ALGORITHM_EQUAL_H
 
+#include <__iterator/segmented_iterator.h>
 #include <__algorithm/comp.h>
 #include <__algorithm/unwrap_iter.h>
 #include <__config>
@@ -17,7 +18,6 @@
 #include <__functional/invoke.h>
 #include <__iterator/distance.h>
 #include <__iterator/iterator_traits.h>
-#include <__iterator/segmented_iterator.h>
 #include <__string/constexpr_c_functions.h>
 #include <__type_traits/desugars_to.h>
 #include <__type_traits/enable_if.h>



More information about the libcxx-commits mailing list