Am 17.12.2023 um 15:46 schrieb Peter J. Holzer:
> Siehe auch "Duff's Device".
Loop-Unrolling geht ohne manuelle Replizierung der einzelnen Statements
in einer Sprache die das erlaubt. Das ist mein unroll.h:
#pragma once
#include <utility>
#include <concepts>
#include <iterator>
#if defined(_MSC_VER)
#define UNROLL_FORCEINLINE __forceinline inline
#elif defined(__GNUC__) || defined(__clang__)
#define UNROLL_FORCEINLINE __attribute__((always_inline)) inline
#else
#define UNROLL_FORCEINLINE inline
#endif
template<size_t N, typename Fn>
requires requires( Fn fn ) { { fn.template operator ()<(size_t)N - 1>()
} -> std::convertible_to<bool>; }
UNROLL_FORCEINLINE bool unroll( Fn fn )
{
auto unroll_n = [&]<size_t ... Indices>( std::index_sequence<Indices
...> ) -> bool
{
return (fn.template operator ()<Indices>() && ...);
};
return unroll_n( std::make_index_sequence<N>() );
}
template<size_t N, typename Fn>
requires requires( Fn fn ) { { fn.template operator ()<(size_t)N - 1>()
} -> std::same_as<void>; }
UNROLL_FORCEINLINE void unroll( Fn fn )
{
unroll<N>( [&]<size_t I>() { fn.template operator ()<I>(); return true;
} );
}
template<std::size_t N, std::random_access_iterator RandomIt, typename Fn>
requires requires( Fn fn, std::iter_common_reference_t<RandomIt> elem )
{ { fn.template operator()<(size_t)-1>( elem ) } -> std::same_as<bool>; }
UNROLL_FORCEINLINE RandomIt unroll_for_each( RandomIt begin, RandomIt
end, Fn fn )
{
if constexpr( N > 1 )
for( ; end - begin >= N && unroll<N>( [&]<size_t I>() { return
fn.template operator ()<I>( begin[I] ); } ); begin += N );
for( ; begin != end && fn.template operator ()<(size_t)-1>( *begin );
++begin );
return begin;
}
template<std::size_t N, std::random_access_iterator RandomIt, typename Fn>
requires requires( Fn fn, std::iter_common_reference_t<RandomIt> elem )
{ { fn.template operator()<(size_t)-1>( elem ) } -> std::same_as<void>; }
UNROLL_FORCEINLINE RandomIt unroll_for_each( RandomIt begin, RandomIt
end, Fn fn )
{
return unroll_for_each<N>( begin, end,
[&]<size_t I>( std::iter_common_reference_t<RandomIt> &value ) {
fn.template operator ()<I>( value ); return true; } );
}
Damit macht man dann sowas wie:
vector<int> vi( ... );
..
int sum = 0;
unroll_for_each<5>( vi.begin(), vi.end(),
[&]<size_t I>( int elem ) { sum += elem; } );