From 39292ed736663d9e516b4420d7037dd696c73fd5 Mon Sep 17 00:00:00 2001 From: Mike Jarvis Date: Fri, 11 Jul 2025 21:55:46 -0400 Subject: [PATCH 1/3] Implement binary version of make_index_sequence --- include/pybind11/detail/common.h | 38 +++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/include/pybind11/detail/common.h b/include/pybind11/detail/common.h index 6f3de41458..b087092e64 100644 --- a/include/pybind11/detail/common.h +++ b/include/pybind11/detail/common.h @@ -720,14 +720,42 @@ using std::make_index_sequence; #else template struct index_sequence {}; -template -struct make_index_sequence_impl : make_index_sequence_impl {}; -template -struct make_index_sequence_impl<0, S...> { +// Comments about the algorithm below. +// +// Credit: This is based on an algorithm by taocpp here: +// https://github.com/taocpp/sequences/blob/main/include/tao/seq/make_integer_sequence.hpp +// but significantly simplified. +// +// We build up a sequence S by repeatedly doubling its length and sometimes adding 1 to the end. +// E.g. if the current S is 0...3, then we either go to 0...7 or 0...8 on the next pass. +// The goal is to end with S = 0...N-1. +// The key insight is that the times we need to add an additional digit to S correspond +// exactly to the 1's in the binary representation of the number N. +// +// Invariants: +// - digit is a power of 2 +// - N_digit_is_1 is whether N's binary representation has a 1 in that digit's position. +// - end <= N +// - S is 0...end-1. +// - if digit > 0, end * digit * 2 <= N < (end+1) * digit * 2 +// +// The process starts with digit > N, end = 0, and S is empty. +// Ths process concludes with digit=0, in which case, end == N and S is 0...N-1. + +template // N_digit_is_1=false +struct make_index_sequence_impl : + make_index_sequence_impl {}; +template +struct make_index_sequence_impl : + make_index_sequence_impl {}; +template +struct make_index_sequence_impl<0, false, N, end, S...> { using type = index_sequence; }; +constexpr size_t next_power_of_2(size_t N) +{ return N == 0 ? 1 : next_power_of_2(N>>1)<<1; } template -using make_index_sequence = typename make_index_sequence_impl::type; +using make_index_sequence = typename make_index_sequence_impl::type; #endif /// Make an index sequence of the indices of true arguments From 7eef026d7ef16c608194af0631abd449c2571a6c Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 12 Jul 2025 02:40:16 +0000 Subject: [PATCH 2/3] style: pre-commit fixes --- include/pybind11/detail/common.h | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/include/pybind11/detail/common.h b/include/pybind11/detail/common.h index b087092e64..3cfd80ec93 100644 --- a/include/pybind11/detail/common.h +++ b/include/pybind11/detail/common.h @@ -743,19 +743,26 @@ struct index_sequence {}; // Ths process concludes with digit=0, in which case, end == N and S is 0...N-1. template // N_digit_is_1=false -struct make_index_sequence_impl : - make_index_sequence_impl {}; +struct make_index_sequence_impl + : make_index_sequence_impl { +}; template -struct make_index_sequence_impl : - make_index_sequence_impl {}; +struct make_index_sequence_impl + : make_index_sequence_impl {}; template struct make_index_sequence_impl<0, false, N, end, S...> { using type = index_sequence; }; -constexpr size_t next_power_of_2(size_t N) -{ return N == 0 ? 1 : next_power_of_2(N>>1)<<1; } +constexpr size_t next_power_of_2(size_t N) { return N == 0 ? 1 : next_power_of_2(N >> 1) << 1; } template -using make_index_sequence = typename make_index_sequence_impl::type; +using make_index_sequence = + typename make_index_sequence_impl::type; #endif /// Make an index sequence of the indices of true arguments From df0e730bbea6b4e6a0ab898c96a9f9ca1add22e1 Mon Sep 17 00:00:00 2001 From: Mike Jarvis Date: Fri, 11 Jul 2025 22:43:52 -0400 Subject: [PATCH 3/3] typo --- include/pybind11/detail/common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/pybind11/detail/common.h b/include/pybind11/detail/common.h index 3cfd80ec93..126e428c30 100644 --- a/include/pybind11/detail/common.h +++ b/include/pybind11/detail/common.h @@ -740,7 +740,7 @@ struct index_sequence {}; // - if digit > 0, end * digit * 2 <= N < (end+1) * digit * 2 // // The process starts with digit > N, end = 0, and S is empty. -// Ths process concludes with digit=0, in which case, end == N and S is 0...N-1. +// The process concludes with digit=0, in which case, end == N and S is 0...N-1. template // N_digit_is_1=false struct make_index_sequence_impl