#pragma once #include "constant_integral.hip.hpp" template struct static_for_impl { template __host__ __device__ void operator()(F f) const { static_assert(Remaining % Increment == 0, "wrong! Remaining % Increment != 0"); static_assert(Increment <= Remaining, "will go out-of-range"); f(Number{}); static_for_impl{}(f); } }; template struct static_for_impl { template __host__ __device__ void operator()(F) const { // no work left, just return return; } }; template struct static_for { template __host__ __device__ void operator()(F f) const { static_assert(NBegin < NEnd, "Wrong! we should have NBegin < NEnd"); static_assert((NEnd - NBegin) % Increment == 0, "Wrong! should satisfy (NEnd - NBegin) % Increment == 0"); static_for_impl{}(f); } }; template struct static_const_reduce_n { template __host__ __device__ constexpr auto operator()(F f, Reduce r) const { static_assert(NLoop > 1, "out-of-range"); constexpr auto a = f(Number{}); auto b = static_const_reduce_n{}(f, r); // TODO: cannot use constexpr here, weird return r(a, b); } }; template <> struct static_const_reduce_n<1> { template __host__ __device__ constexpr auto operator()(F f, Reduce) const { return f(Number<0>{}); } }; #if 0 template __host__ __device__ constexpr auto unpacker(F f) { return [=](auto xs_array){ f(xs...); }; } #endif struct forwarder { template __host__ __device__ constexpr T operator()(T&& x) const { return std::forward(x); } }; // Emulate compile time if statement for C++14 // Get the idea from // "https://baptiste-wicht.com/posts/2015/07/simulate-static_if-with-c11c14.html" // TODO: use if constexpr, when C++17 is supported template struct static_if { }; template <> struct static_if { using Type = static_if; template __host__ __device__ constexpr auto operator()(F f) const { // This is a trick for compiler: // Pass forwarder to lambda "f" as "auto" argument, and maks sure "f" will use it, // this will make "f" a generic lambda, so that "f" won't be compiled until here f(forwarder{}); return Type{}; } template __host__ __device__ static constexpr auto else_(F) { return Type{}; } }; template <> struct static_if { using Type = static_if; template __host__ __device__ constexpr auto operator()(F) const { return Type{}; } template __host__ __device__ static constexpr auto else_(F f) { // This is a trick for compiler: // Pass forwarder to lambda "f" as "auto" argument, and maks sure "f" will use it, // this will make "f" a generic lambda, so that "f" won't be compiled until here f(forwarder{}); return Type{}; } };