[libcxx-commits] [libcxx] Speed up the time complexity of pre-C++20 operator<(std::tuple, std::tuple) (PR #214646)

via libcxx-commits libcxx-commits at lists.llvm.org
Fri Aug 7 10:48:12 PDT 2026


https://github.com/higher-performance updated https://github.com/llvm/llvm-project/pull/214646

>From e7ba21527090c7959a5303dcaf0b2e20abf0a15e Mon Sep 17 00:00:00 2001
From: higher-performance <higher.performance.github at gmail.com>
Date: Fri, 7 Aug 2026 02:33:01 -0400
Subject: [PATCH] Speed up the time complexity of pre-C++20
 operator<(std::tuple, std::tuple)

Currently, the pre-C++20 implementation of `operator<()` on `std::tuple` takes at least quadratic time to compile, since it is recursive and each recursion is only one element smaller.
This commit switches to divide-and-conquer to speed up the recursion to something between O(n) and O(n^1.6), depending on inlining depth, assuming `std::get` is constant-time.
---
 libcxx/include/tuple | 35 ++++++++++++++++++-----------------
 1 file changed, 18 insertions(+), 17 deletions(-)

diff --git a/libcxx/include/tuple b/libcxx/include/tuple
index 2f0127bc7388d..768af0ff9b743 100644
--- a/libcxx/include/tuple
+++ b/libcxx/include/tuple
@@ -1191,24 +1191,25 @@ operator!=(const tuple<_Tp...>& __x, const tuple<_Up...>& __y) {
   return !(__x == __y);
 }
 
-template <size_t _Ip>
+template <size_t _Ip, size_t _Jp>
 struct __tuple_less {
-  template <class _Tp, class _Up>
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool operator()(const _Tp& __x, const _Up& __y) {
-    const size_t __idx = tuple_size<_Tp>::value - _Ip;
-    if (std::get<__idx>(__x) < std::get<__idx>(__y))
-      return true;
-    if (std::get<__idx>(__y) < std::get<__idx>(__x))
+  template <class _Tuple1, class _Tuple2>
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool
+  operator()(const _Tuple1& __x, const _Tuple2& __y) const {
+    if constexpr ((_Jp - _Ip) >= 2) {
+      const __tuple_less<_Ip, _Ip + ((_Jp - _Ip) >> 1)> __left;
+      if (__left(__x, __y)) {
+        return true;
+      }
+      if (__left(__y, __x)) {
+        return false;
+      }
+      return __tuple_less<_Ip + ((_Jp - _Ip) >> 1), _Jp>()(__x, __y);
+    } else if constexpr ((_Jp - _Ip) == 1) {
+      return std::get<_Ip>(__x) < std::get<_Ip>(__y);
+    } else {
       return false;
-    return __tuple_less<_Ip - 1>()(__x, __y);
-  }
-};
-
-template <>
-struct __tuple_less<0> {
-  template <class _Tp, class _Up>
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool operator()(const _Tp&, const _Up&) {
-    return false;
+    }
   }
 };
 
@@ -1216,7 +1217,7 @@ template <class... _Tp, class... _Up>
 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool
 operator<(const tuple<_Tp...>& __x, const tuple<_Up...>& __y) {
   static_assert(sizeof...(_Tp) == sizeof...(_Up), "Can't compare tuples of different sizes");
-  return __tuple_less<sizeof...(_Tp)>()(__x, __y);
+  return __tuple_less<0, sizeof...(_Tp)>()(__x, __y);
 }
 
 template <class... _Tp, class... _Up>



More information about the libcxx-commits mailing list