151c0b2f7Stbbdev /*
2b15aabb3Stbbdev     Copyright (c) 2020-2021 Intel Corporation
351c0b2f7Stbbdev 
451c0b2f7Stbbdev     Licensed under the Apache License, Version 2.0 (the "License");
551c0b2f7Stbbdev     you may not use this file except in compliance with the License.
651c0b2f7Stbbdev     You may obtain a copy of the License at
751c0b2f7Stbbdev 
851c0b2f7Stbbdev         http://www.apache.org/licenses/LICENSE-2.0
951c0b2f7Stbbdev 
1051c0b2f7Stbbdev     Unless required by applicable law or agreed to in writing, software
1151c0b2f7Stbbdev     distributed under the License is distributed on an "AS IS" BASIS,
1251c0b2f7Stbbdev     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1351c0b2f7Stbbdev     See the License for the specific language governing permissions and
1451c0b2f7Stbbdev     limitations under the License.
1551c0b2f7Stbbdev */
1651c0b2f7Stbbdev 
1751c0b2f7Stbbdev #ifndef __TBB_test_common_parallel_invoke_common_H
1851c0b2f7Stbbdev #define __TBB_test_common_parallel_invoke_common_H
1951c0b2f7Stbbdev 
20*478de5b1Stbbdev #include "config.h"
21*478de5b1Stbbdev 
2251c0b2f7Stbbdev #include <cstddef>
2351c0b2f7Stbbdev #include <tuple>
2451c0b2f7Stbbdev 
2549e08aacStbbdev #include "oneapi/tbb/parallel_invoke.h"
2649e08aacStbbdev #include "oneapi/tbb/global_control.h"
2751c0b2f7Stbbdev 
28b15aabb3Stbbdev #include "dummy_body.h"
29b15aabb3Stbbdev 
3051c0b2f7Stbbdev // Helps generate a tuple of functional objects
3151c0b2f7Stbbdev template<std::size_t Counter, template <std::size_t> class Functor, class Generator, typename... Fs>
3251c0b2f7Stbbdev struct generate_tuple_impl :
3351c0b2f7Stbbdev     public generate_tuple_impl<Counter - 1, Functor, Generator, typename Generator::template type<Functor, Counter - 1>, Fs...> {};
3451c0b2f7Stbbdev 
3551c0b2f7Stbbdev template<template <std::size_t> class Functor, class Generator, typename... Fs>
3651c0b2f7Stbbdev struct generate_tuple_impl <0, Functor, Generator, Fs...> {
3751c0b2f7Stbbdev     using type = std::tuple<Fs...>;
3851c0b2f7Stbbdev };
3951c0b2f7Stbbdev 
4051c0b2f7Stbbdev template<std::size_t Size, template <std::size_t> class Functor, class Generator>
4151c0b2f7Stbbdev using generate_tuple = typename generate_tuple_impl<Size, Functor, Generator>::type;
4251c0b2f7Stbbdev 
4351c0b2f7Stbbdev // Defines how generate_tuple should propagate Counter to the tuple members
4451c0b2f7Stbbdev struct generator {
4551c0b2f7Stbbdev     template <template <std::size_t> class Functor, std::size_t NonTypeArg>
4651c0b2f7Stbbdev     using type = Functor<NonTypeArg>;
4751c0b2f7Stbbdev };
4851c0b2f7Stbbdev 
4951c0b2f7Stbbdev template <std::size_t Fixed>
5051c0b2f7Stbbdev struct fixed_generator {
5151c0b2f7Stbbdev     template <template <std::size_t> class Functor, std::size_t NonTypeArg>
5251c0b2f7Stbbdev     using type = Functor<Fixed>;
5351c0b2f7Stbbdev };
5451c0b2f7Stbbdev 
5551c0b2f7Stbbdev template<std::size_t LevelTaskCount, std::size_t MaxDepth, std::size_t WorkSize>
5651c0b2f7Stbbdev struct invoke_tree {
5751c0b2f7Stbbdev     struct invoke_tree_leaf {
5851c0b2f7Stbbdev         static constexpr std::size_t size = WorkSize;
59b15aabb3Stbbdev         void operator()() const { utils::doDummyWork(size); }
6051c0b2f7Stbbdev     };
6151c0b2f7Stbbdev 
6251c0b2f7Stbbdev     // Make invoke_tree_leaf composable with generate_tuple interface
6351c0b2f7Stbbdev     template <std::size_t NonTypeArg>
6451c0b2f7Stbbdev     using generating_leaf_functor = invoke_tree_leaf;
6551c0b2f7Stbbdev 
6651c0b2f7Stbbdev     template<std::size_t CurrentDepth>
6751c0b2f7Stbbdev     struct invoke_tree_node {
6851c0b2f7Stbbdev         template<typename... Fs>
6951c0b2f7Stbbdev         void invoker(const std::tuple<Fs...>&) const {
7051c0b2f7Stbbdev             tbb::parallel_invoke(Fs()...);
7151c0b2f7Stbbdev         }
7251c0b2f7Stbbdev 
7351c0b2f7Stbbdev         // Template alias to workaround the strange Visual Studio issue
7451c0b2f7Stbbdev         template<std::size_t Depth>
7551c0b2f7Stbbdev         using generating_node_functor = invoke_tree_node<Depth>;
7651c0b2f7Stbbdev 
7751c0b2f7Stbbdev         void create_level(/*is_final_level*/std::false_type) const {
7851c0b2f7Stbbdev             invoker(generate_tuple<LevelTaskCount, generating_node_functor, fixed_generator<CurrentDepth + 1>>{});
7951c0b2f7Stbbdev         }
8051c0b2f7Stbbdev 
8151c0b2f7Stbbdev         void create_level(/*is_final_level*/std::true_type) const {
8251c0b2f7Stbbdev             invoker(generate_tuple<LevelTaskCount, generating_leaf_functor, generator>());
8351c0b2f7Stbbdev         }
8451c0b2f7Stbbdev 
8551c0b2f7Stbbdev         void operator()() const {
8651c0b2f7Stbbdev             create_level(/*is_final_level*/std::integral_constant<bool, CurrentDepth == MaxDepth>());
8751c0b2f7Stbbdev         }
8851c0b2f7Stbbdev     };
8951c0b2f7Stbbdev 
9051c0b2f7Stbbdev     static void generate_and_run() {
9151c0b2f7Stbbdev         invoke_tree_node<1> tree_root;
9251c0b2f7Stbbdev         tree_root();
9351c0b2f7Stbbdev     }
9451c0b2f7Stbbdev };
9551c0b2f7Stbbdev 
9651c0b2f7Stbbdev template<std::size_t TaskCount, template<std::size_t> class Functor>
9751c0b2f7Stbbdev class parallel_invoke_call {
9851c0b2f7Stbbdev     template<typename... Fs>
9951c0b2f7Stbbdev     static void invoke_tuple_args(tbb::task_group_context* context_ptr, const std::tuple<Fs...>&) {
10051c0b2f7Stbbdev         if (context_ptr != nullptr) {
10151c0b2f7Stbbdev             tbb::parallel_invoke(Fs()..., *context_ptr);
10251c0b2f7Stbbdev         } else {
10351c0b2f7Stbbdev             tbb::parallel_invoke(Fs()...);
10451c0b2f7Stbbdev         }
10551c0b2f7Stbbdev     }
10651c0b2f7Stbbdev 
10751c0b2f7Stbbdev public:
10851c0b2f7Stbbdev     static void perform(tbb::task_group_context* context_ptr = nullptr) {
10951c0b2f7Stbbdev         invoke_tuple_args(context_ptr, generate_tuple<TaskCount, Functor, generator>{});
11051c0b2f7Stbbdev     }
11151c0b2f7Stbbdev };
11251c0b2f7Stbbdev 
11351c0b2f7Stbbdev #endif // __TBB_test_common_parallel_invoke_common_H
114