[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