@@ -157,31 +157,53 @@ using default_policy = KERNEL_FLOAT_POLICY;
157157
158158namespace detail {
159159
160+ //
160161template <typename Policy, typename F, size_t N, typename Output, typename ... Args>
161- struct apply_base_impl {
162+ struct apply_fallback_impl {
162163 KERNEL_FLOAT_INLINE static void call (F fun, Output* output, const Args*... args) {
163- #pragma unroll
164- for (size_t i = 0 ; i < N; i++) {
165- output[i] = fun (args[i]...);
166- }
164+ static_assert (N > 0 , " operation not implemented" );
167165 }
168166};
169167
168+ template <typename Policy, typename F, size_t N, typename Output, typename ... Args>
169+ struct apply_base_impl : apply_fallback_impl<Policy, F, N, Output, Args...> {};
170+
170171template <typename Policy, typename F, size_t N, typename Output, typename ... Args>
171172struct apply_impl : apply_base_impl<Policy, F, N, Output, Args...> {};
172173
174+ // `fast_policy` falls back to `accurate_policy`
173175template <typename F, size_t N, typename Output, typename ... Args>
174- struct apply_base_impl <fast_policy, F, N, Output, Args...>:
176+ struct apply_fallback_impl <fast_policy, F, N, Output, Args...>:
175177 apply_impl<accurate_policy, F, N, Output, Args...> {};
176178
179+ // `approx_policy` falls back to `fast_policy`
177180template <typename F, size_t N, typename Output, typename ... Args>
178- struct apply_base_impl <approx_policy, F, N, Output, Args...>:
181+ struct apply_fallback_impl <approx_policy, F, N, Output, Args...>:
179182 apply_impl<fast_policy, F, N, Output, Args...> {};
180183
184+ // `approx_level_policy` falls back to `approx_policy`
181185template <int Level, typename F, size_t N, typename Output, typename ... Args>
182- struct apply_base_impl <approx_level_policy<Level>, F, N, Output, Args...>:
186+ struct apply_fallback_impl <approx_level_policy<Level>, F, N, Output, Args...>:
183187 apply_impl<approx_policy, F, N, Output, Args...> {};
184188
189+ template <typename F, typename Output, typename ... Args>
190+ struct invoke_impl {
191+ KERNEL_FLOAT_INLINE static Output call (F fun, Args... args) {
192+ return fun (args...);
193+ }
194+ };
195+
196+ // Only for `accurate_policy` do we implement `apply_impl`, the others will fall back to `apply_base_impl`.
197+ template <typename F, size_t N, typename Output, typename ... Args>
198+ struct apply_impl <accurate_policy, F, N, Output, Args...> {
199+ KERNEL_FLOAT_INLINE static void call (F fun, Output* output, const Args*... args) {
200+ #pragma unroll
201+ for (size_t i = 0 ; i < N; i++) {
202+ output[i] = invoke_impl<F, Output, Args...>::call (fun, args[i]...);
203+ }
204+ }
205+ };
206+
185207template <typename Policy, typename F, size_t N, typename Output, typename ... Args>
186208struct map_impl {
187209 static constexpr size_t packet_size = preferred_vector_size<Output>::value;
0 commit comments