@@ -720,14 +720,49 @@ using std::make_index_sequence;
720
720
#else
721
721
template <size_t ...>
722
722
struct 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...> {
727
760
using type = index_sequence<S...>;
728
761
};
762
+ constexpr size_t next_power_of_2 (size_t N) { return N == 0 ? 1 : next_power_of_2 (N >> 1 ) << 1 ; }
729
763
template <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;
731
766
#endif
732
767
733
768
// / Make an index sequence of the indices of true arguments
0 commit comments