@@ -720,14 +720,49 @@ using std::make_index_sequence;
720720#else
721721template <size_t ...>
722722struct index_sequence {};
723- template <size_t N, size_t ... S>
724- struct make_index_sequence_impl : make_index_sequence_impl<N - 1 , N - 1 , S...> {};
725- template <size_t ... S>
726- struct make_index_sequence_impl <0 , S...> {
723+ // Comments about the algorithm below.
724+ //
725+ // Credit: This is based on an algorithm by taocpp here:
726+ // https://github.com/taocpp/sequences/blob/main/include/tao/seq/make_integer_sequence.hpp
727+ // but significantly simplified.
728+ //
729+ // We build up a sequence S by repeatedly doubling its length and sometimes adding 1 to the end.
730+ // E.g. if the current S is 0...3, then we either go to 0...7 or 0...8 on the next pass.
731+ // The goal is to end with S = 0...N-1.
732+ // The key insight is that the times we need to add an additional digit to S correspond
733+ // exactly to the 1's in the binary representation of the number N.
734+ //
735+ // Invariants:
736+ // - digit is a power of 2
737+ // - N_digit_is_1 is whether N's binary representation has a 1 in that digit's position.
738+ // - end <= N
739+ // - S is 0...end-1.
740+ // - if digit > 0, end * digit * 2 <= N < (end+1) * digit * 2
741+ //
742+ // The process starts with digit > N, end = 0, and S is empty.
743+ // The process concludes with digit=0, in which case, end == N and S is 0...N-1.
744+
745+ template <size_t digit, bool N_digit_is_1, size_t N, size_t end, size_t ... S> // N_digit_is_1=false
746+ struct make_index_sequence_impl
747+ : make_index_sequence_impl<digit / 2 , (N & (digit / 2 )) != 0 , N, 2 * end, S..., (S + end)...> {
748+ };
749+ template <size_t digit, size_t N, size_t end, size_t ... S>
750+ struct make_index_sequence_impl <digit, true , N, end, S...>
751+ : make_index_sequence_impl<digit / 2 ,
752+ (N & (digit / 2 )) != 0 ,
753+ N,
754+ 2 * end + 1 ,
755+ S...,
756+ (S + end)...,
757+ 2 * end> {};
758+ template <size_t N, size_t end, size_t ... S>
759+ struct make_index_sequence_impl <0 , false , N, end, S...> {
727760 using type = index_sequence<S...>;
728761};
762+ constexpr size_t next_power_of_2 (size_t N) { return N == 0 ? 1 : next_power_of_2 (N >> 1 ) << 1 ; }
729763template <size_t N>
730- using make_index_sequence = typename make_index_sequence_impl<N>::type;
764+ using make_index_sequence =
765+ typename make_index_sequence_impl<next_power_of_2(N), false , N, 0 >::type;
731766#endif
732767
733768// / Make an index sequence of the indices of true arguments
0 commit comments