#pragma once

namespace Unroll {

// Helper to force loop unrolling.  Replace this:
//
//    for (int i = 0; i < N; ++i)
//    {
//        WriteTo(&output[i]);
//    }
//
// with this:
//
//    For<0,N>::Do([&](int i)
//    {
//        WriteTo(&output[i]);
//    });
//
template <int From, int To> struct For
{
    // Take func by const& instead && because we need to support both
    // lvalues (like named functions) and rvalues (like lambdas), but
    // it makes no sense to move/forward rvalues since func is called
    // multiple times.
    template <typename Func> static void Do(Func const& func, int i = From)
    {
        func(i);
        For<From + 1, To>::Do(func, i + 1);
    }
};
template <int To> struct For<To, To>
{
    template <typename Func> static void Do(Func const&, int) {}
};

} // namespace Unroll
