151c0b2f7Stbbdev /*
2a088cfa0SKonstantin Boyarinov     Copyright (c) 2020-2023 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 #include "common/test.h"
1851c0b2f7Stbbdev #include "common/utils.h"
1951c0b2f7Stbbdev #include "common/checktype.h"
2051c0b2f7Stbbdev #include "common/spin_barrier.h"
2151c0b2f7Stbbdev #include "common/utils_concurrency_limit.h"
22a088cfa0SKonstantin Boyarinov #include "common/test_invoke.h"
2351c0b2f7Stbbdev 
2449e08aacStbbdev #include "oneapi/tbb/parallel_pipeline.h"
2549e08aacStbbdev #include "oneapi/tbb/global_control.h"
2649e08aacStbbdev #include "oneapi/tbb/task_group.h"
2751c0b2f7Stbbdev 
2851c0b2f7Stbbdev #include <atomic>
2951c0b2f7Stbbdev #include <thread>
3051c0b2f7Stbbdev #include <string.h>
3151c0b2f7Stbbdev #include <memory>
3251c0b2f7Stbbdev #include <tuple>
3351c0b2f7Stbbdev 
3451c0b2f7Stbbdev //! \file conformance_parallel_pipeline.cpp
3551c0b2f7Stbbdev //! \brief Test for [algorithms.parallel_pipeline algorithms.parallel_pipeline.flow_control] specification
3651c0b2f7Stbbdev 
3751c0b2f7Stbbdev constexpr std::size_t n_tokens = 8;
3851c0b2f7Stbbdev 
3951c0b2f7Stbbdev constexpr int max_counter = 1024;
4051c0b2f7Stbbdev 
4151c0b2f7Stbbdev static std::atomic<int> input_counter{ max_counter };
4251c0b2f7Stbbdev 
4351c0b2f7Stbbdev template<typename U>
4451c0b2f7Stbbdev class input_filter {
4551c0b2f7Stbbdev public:
operator ()(oneapi::tbb::flow_control & control) const4649e08aacStbbdev     U operator()( oneapi::tbb::flow_control& control ) const {
4751c0b2f7Stbbdev         if( --input_counter < 0 ) {
4851c0b2f7Stbbdev             control.stop();
4951c0b2f7Stbbdev             input_counter = max_counter;
5051c0b2f7Stbbdev         }
5151c0b2f7Stbbdev         return U();
5251c0b2f7Stbbdev     }
5351c0b2f7Stbbdev };
5451c0b2f7Stbbdev 
5551c0b2f7Stbbdev template<typename T, typename U>
5651c0b2f7Stbbdev class middle_filter {
5751c0b2f7Stbbdev public:
operator ()(T) const5851c0b2f7Stbbdev     U operator()(T) const {
5951c0b2f7Stbbdev         U out{};
6051c0b2f7Stbbdev         return out;
6151c0b2f7Stbbdev     }
6251c0b2f7Stbbdev };
6351c0b2f7Stbbdev 
6451c0b2f7Stbbdev template<typename T>
6551c0b2f7Stbbdev class output_filter {
6651c0b2f7Stbbdev public:
operator ()(T) const6751c0b2f7Stbbdev     void operator()(T ) const {}
6851c0b2f7Stbbdev };
6951c0b2f7Stbbdev 
7049e08aacStbbdev static const oneapi::tbb::filter_mode filter_table[] = { oneapi::tbb::filter_mode::parallel,
7149e08aacStbbdev                                                  oneapi::tbb::filter_mode::serial_in_order,
7249e08aacStbbdev                                                  oneapi::tbb::filter_mode::serial_out_of_order};
7351c0b2f7Stbbdev 
7451c0b2f7Stbbdev template<typename Body, typename... Cotnext>
TestSingleFilter(Body body,Cotnext &...context)7551c0b2f7Stbbdev void TestSingleFilter(Body body, Cotnext&... context) {
7651c0b2f7Stbbdev 
7751c0b2f7Stbbdev     for(int i =0; i <3; i++)
7851c0b2f7Stbbdev     {
7949e08aacStbbdev         oneapi::tbb::filter_mode mode = filter_table[i];
8051c0b2f7Stbbdev 
8149e08aacStbbdev         oneapi::tbb::filter<void, void> one_filter( mode, body );
8249e08aacStbbdev         oneapi::tbb::parallel_pipeline( n_tokens, one_filter, context...   );
8351c0b2f7Stbbdev 
8449e08aacStbbdev         oneapi::tbb::parallel_pipeline( n_tokens, oneapi::tbb::filter<void, void>(mode, body), context... );
8551c0b2f7Stbbdev 
8649e08aacStbbdev         oneapi::tbb::parallel_pipeline( n_tokens, oneapi::tbb::make_filter<void, void>(mode, body), context...);
8751c0b2f7Stbbdev     }
8851c0b2f7Stbbdev }
8951c0b2f7Stbbdev 
TestSingleFilterFunctor()9051c0b2f7Stbbdev void TestSingleFilterFunctor() {
9151c0b2f7Stbbdev 
9251c0b2f7Stbbdev     input_filter<void> i_filter;
9351c0b2f7Stbbdev 
9451c0b2f7Stbbdev     TestSingleFilter(i_filter);
9551c0b2f7Stbbdev 
9649e08aacStbbdev     oneapi::tbb::task_group_context context;
9751c0b2f7Stbbdev     TestSingleFilter(i_filter,  context);
9851c0b2f7Stbbdev }
9951c0b2f7Stbbdev 
10051c0b2f7Stbbdev 
TestSingleFilterLambda()10151c0b2f7Stbbdev void TestSingleFilterLambda() {
10251c0b2f7Stbbdev 
10351c0b2f7Stbbdev 
10449e08aacStbbdev     TestSingleFilter([]( oneapi::tbb::flow_control& control ) {
10551c0b2f7Stbbdev                     if(input_counter-- == 0 ) {
10651c0b2f7Stbbdev                         control.stop();
10751c0b2f7Stbbdev                         input_counter = max_counter;
10851c0b2f7Stbbdev                         }
10951c0b2f7Stbbdev                     } );
11051c0b2f7Stbbdev 
11149e08aacStbbdev     oneapi::tbb::task_group_context context;
11249e08aacStbbdev     TestSingleFilter([]( oneapi::tbb::flow_control& control ) {
11351c0b2f7Stbbdev                      if(input_counter-- == 0 ) {
11451c0b2f7Stbbdev                         control.stop();
11551c0b2f7Stbbdev                         input_counter = max_counter;
11651c0b2f7Stbbdev                         }
11751c0b2f7Stbbdev                     },  context);
11851c0b2f7Stbbdev }
11951c0b2f7Stbbdev 
12051c0b2f7Stbbdev template<typename I, typename O>
RunPipeline(const oneapi::tbb::filter<I,O> & filter)12149e08aacStbbdev void RunPipeline(const oneapi::tbb::filter<I, O> &filter)
12251c0b2f7Stbbdev {
12351c0b2f7Stbbdev     bool flag{false};
12451c0b2f7Stbbdev 
12549e08aacStbbdev     auto f_beg = oneapi::tbb::make_filter<void, I>(oneapi::tbb::filter_mode::serial_out_of_order,
12649e08aacStbbdev                                         [&flag](oneapi::tbb::flow_control& fc) -> I{
12751c0b2f7Stbbdev                                             if(flag) {
12851c0b2f7Stbbdev                                                 fc.stop();
12951c0b2f7Stbbdev                                             }
13051c0b2f7Stbbdev                                             flag = true;
13151c0b2f7Stbbdev                                             return I();
13251c0b2f7Stbbdev                                         });
13351c0b2f7Stbbdev 
13449e08aacStbbdev     auto f_end = oneapi::tbb::make_filter<O, void>(oneapi::tbb::filter_mode::serial_in_order,
13551c0b2f7Stbbdev                                             [](O) {});
13651c0b2f7Stbbdev 
13749e08aacStbbdev     oneapi::tbb::parallel_pipeline(n_tokens, f_beg & filter & f_end);
13851c0b2f7Stbbdev }
13951c0b2f7Stbbdev 
RunPipeline(const oneapi::tbb::filter<void,void> & filter)14049e08aacStbbdev void RunPipeline(const oneapi::tbb::filter<void, void> &filter)
14151c0b2f7Stbbdev {
14249e08aacStbbdev     oneapi::tbb::parallel_pipeline(n_tokens, filter);
14351c0b2f7Stbbdev }
14451c0b2f7Stbbdev 
14551c0b2f7Stbbdev template<typename Iterator1, typename Iterator2>
RootSequence(Iterator1 first,Iterator1 last,Iterator2 res)14651c0b2f7Stbbdev void RootSequence( Iterator1 first, Iterator1 last, Iterator2 res) {
14751c0b2f7Stbbdev     using ValueType = typename Iterator1::value_type;
14849e08aacStbbdev     oneapi::tbb::parallel_pipeline( n_tokens,
14949e08aacStbbdev         oneapi::tbb::make_filter<void,ValueType>(
15049e08aacStbbdev             oneapi::tbb::filter_mode::serial_in_order,
15149e08aacStbbdev             [&first, &last](oneapi::tbb::flow_control& fc)-> ValueType{
15251c0b2f7Stbbdev                 if( first<last ) {
15351c0b2f7Stbbdev                     ValueType val  = *first;
15451c0b2f7Stbbdev                     ++first;
15551c0b2f7Stbbdev                     return val;
15651c0b2f7Stbbdev                  } else {
15751c0b2f7Stbbdev                     fc.stop();
15851c0b2f7Stbbdev                     return ValueType{};
15951c0b2f7Stbbdev                 }
16051c0b2f7Stbbdev             }
16151c0b2f7Stbbdev         ) &
16249e08aacStbbdev         oneapi::tbb::make_filter<ValueType,ValueType>(
16349e08aacStbbdev             oneapi::tbb::filter_mode::parallel,
16451c0b2f7Stbbdev             [](ValueType p){return p*p;}
16551c0b2f7Stbbdev         ) &
16649e08aacStbbdev         oneapi::tbb::make_filter<ValueType,void>(
16749e08aacStbbdev             oneapi::tbb::filter_mode::serial_in_order,
16851c0b2f7Stbbdev             [&res](ValueType x) {
16951c0b2f7Stbbdev                 *res = x;
17051c0b2f7Stbbdev                 ++res; }
17151c0b2f7Stbbdev         )
17251c0b2f7Stbbdev     );
17351c0b2f7Stbbdev }
17451c0b2f7Stbbdev 
17551c0b2f7Stbbdev //! Testing pipeline correctness
17651c0b2f7Stbbdev //! \brief \ref interface \ref requirement
17751c0b2f7Stbbdev TEST_CASE("Testing pipeline correctness")
17851c0b2f7Stbbdev {
17951c0b2f7Stbbdev     std::vector<double> input(max_counter);
18051c0b2f7Stbbdev     std::vector<double> output(max_counter);
18151c0b2f7Stbbdev     for(std::size_t i = 0; i < max_counter; i++)
18251c0b2f7Stbbdev         input[i] = (double)i;
18351c0b2f7Stbbdev 
18451c0b2f7Stbbdev     RootSequence(input.cbegin(), input.cend(), output.begin());
18551c0b2f7Stbbdev     for(int  i = 0; i < max_counter; i++) {
18651c0b2f7Stbbdev         CHECK_MESSAGE(output[i] == input[i]*input[i], "pipeline result is incorrect");
18751c0b2f7Stbbdev     }
18851c0b2f7Stbbdev }
18951c0b2f7Stbbdev 
19051c0b2f7Stbbdev //! Testing pipeline with single filter
19151c0b2f7Stbbdev //! \brief \ref interface \ref requirement
19251c0b2f7Stbbdev TEST_CASE("Testing pipeline with single filter")
19351c0b2f7Stbbdev {
19451c0b2f7Stbbdev     TestSingleFilterFunctor();
19551c0b2f7Stbbdev     TestSingleFilterLambda();
19651c0b2f7Stbbdev }
19751c0b2f7Stbbdev 
19851c0b2f7Stbbdev //! Testing single filter with different ways of creation
19951c0b2f7Stbbdev //! \brief \ref interface \ref requirement
20051c0b2f7Stbbdev TEST_CASE_TEMPLATE("Filter creation testing", T, std::tuple<size_t, int>,
20151c0b2f7Stbbdev                                                  std::tuple<int, double>,
20251c0b2f7Stbbdev                                                  std::tuple<unsigned int*, size_t>,
20351c0b2f7Stbbdev                                                  std::tuple<unsigned short, unsigned short*>,
20451c0b2f7Stbbdev                                                  std::tuple<double*, unsigned short*>,
20551c0b2f7Stbbdev                                                  std::tuple<std::unique_ptr<int>, std::unique_ptr<int> >)
20651c0b2f7Stbbdev {
20751c0b2f7Stbbdev     using I = typename std::tuple_element<0, T>::type;
20851c0b2f7Stbbdev     using O = typename std::tuple_element<1, T>::type;
20951c0b2f7Stbbdev     for(int i = 0; i < 3; i++)
21051c0b2f7Stbbdev     {
21149e08aacStbbdev         oneapi::tbb::filter_mode mode = filter_table[i];
21249e08aacStbbdev         oneapi::tbb::filter<I, O> default_filter;
21351c0b2f7Stbbdev 
__anon5895f2ca0802(I)21449e08aacStbbdev         auto made_filter1 = oneapi::tbb::make_filter<I,O>(mode, [](I)->O{return O();});
21549e08aacStbbdev         static_assert(std::is_same<oneapi::tbb::filter<I, O>, decltype(made_filter1)>::value, "make_filter wrong result type");
21651c0b2f7Stbbdev         RunPipeline(made_filter1);
21751c0b2f7Stbbdev 
__anon5895f2ca0902(I)21849e08aacStbbdev         auto made_filter2 = oneapi::tbb::make_filter(mode, [](I)->O{return O();});
21949e08aacStbbdev         static_assert(std::is_same<oneapi::tbb::filter<I, O>, decltype(made_filter2)>::value, "make_filter wrong result type");
22051c0b2f7Stbbdev         RunPipeline(made_filter2);
22151c0b2f7Stbbdev 
__anon5895f2ca0a02(I)22249e08aacStbbdev         oneapi::tbb::filter<I, O> one_filter(mode, [](I)->O{return O();});
22351c0b2f7Stbbdev         RunPipeline(one_filter);
22451c0b2f7Stbbdev 
22549e08aacStbbdev         oneapi::tbb::filter<I, O> copy_filter(one_filter);
22651c0b2f7Stbbdev         RunPipeline(one_filter);
22751c0b2f7Stbbdev 
22851c0b2f7Stbbdev         default_filter = copy_filter;
22951c0b2f7Stbbdev         RunPipeline(default_filter);
23051c0b2f7Stbbdev         default_filter.clear();
23151c0b2f7Stbbdev     }
23251c0b2f7Stbbdev }
23351c0b2f7Stbbdev 
23451c0b2f7Stbbdev //! Testing filters concatenation
23551c0b2f7Stbbdev //! \brief \ref interface \ref requirement
23651c0b2f7Stbbdev TEST_CASE_TEMPLATE("Testing filters concatenation", T, std::tuple<size_t, int>,
23751c0b2f7Stbbdev                                                        std::tuple<int, double>,
23851c0b2f7Stbbdev                                                        std::tuple<unsigned int*, size_t>,
23951c0b2f7Stbbdev                                                        std::tuple<unsigned short, unsigned short*>,
24051c0b2f7Stbbdev                                                        std::tuple<double*, unsigned short*>,
24151c0b2f7Stbbdev                                                        std::tuple<std::unique_ptr<int>, std::unique_ptr<int> >)
24251c0b2f7Stbbdev {
24351c0b2f7Stbbdev     using I = typename std::tuple_element<0, T>::type;
24451c0b2f7Stbbdev     using O = typename std::tuple_element<1, T>::type;
24551c0b2f7Stbbdev 
24651c0b2f7Stbbdev     for(int fi = 0; fi< 27; fi++)
24751c0b2f7Stbbdev     {
24851c0b2f7Stbbdev         int i = fi%3;
24951c0b2f7Stbbdev         int j = (fi/3)%3;
25051c0b2f7Stbbdev         int k = (fi/9);
25149e08aacStbbdev         auto filter_chain = oneapi::tbb::filter<void, I>(filter_table[i], input_filter<I>()) &
25249e08aacStbbdev                             oneapi::tbb::filter<I, O>(filter_table[j], middle_filter<I,O>()) &
25349e08aacStbbdev                             oneapi::tbb::filter<O, void>(filter_table[k], output_filter<O>());
25451c0b2f7Stbbdev         RunPipeline(filter_chain);
25551c0b2f7Stbbdev 
25649e08aacStbbdev         oneapi::tbb::filter<void, I> filter1 = oneapi::tbb::filter<void, I>(filter_table[i], input_filter<I>());
25749e08aacStbbdev         oneapi::tbb::filter<I, O> filter2 = oneapi::tbb::filter<I, O>(filter_table[j], middle_filter<I,O>());
25849e08aacStbbdev         oneapi::tbb::filter<O, void> filter3 = oneapi::tbb::filter<O, void>(filter_table[k], output_filter<O>());
25951c0b2f7Stbbdev 
26051c0b2f7Stbbdev         auto fitler12 = filter1 & filter2;
26151c0b2f7Stbbdev         auto fitler23 = filter2 & filter3;
26251c0b2f7Stbbdev         auto fitler123 = filter1 & filter2 & filter3;
26351c0b2f7Stbbdev 
26451c0b2f7Stbbdev         RunPipeline(fitler12 & filter3);
26551c0b2f7Stbbdev         RunPipeline(filter1 & fitler23);
26651c0b2f7Stbbdev         RunPipeline(fitler123);
26751c0b2f7Stbbdev     }
26851c0b2f7Stbbdev }
26951c0b2f7Stbbdev 
doWork()27051c0b2f7Stbbdev void doWork() {
27151c0b2f7Stbbdev     for (int i = 0; i < 10; ++i)
272b15aabb3Stbbdev         utils::yield();
27351c0b2f7Stbbdev }
27451c0b2f7Stbbdev 
27551c0b2f7Stbbdev //! Testing filter modes
27651c0b2f7Stbbdev //! \brief \ref interface \ref requirement
27751c0b2f7Stbbdev TEST_CASE("Testing filter modes")
27851c0b2f7Stbbdev {
27951c0b2f7Stbbdev     for ( auto concurrency_level : utils::concurrency_range() )
28051c0b2f7Stbbdev     {
28149e08aacStbbdev         oneapi::tbb::global_control control(oneapi::tbb::global_control::max_allowed_parallelism, concurrency_level);
28251c0b2f7Stbbdev 
2833b045217SAlexei Katranov         short serial_checker{0};
28449e08aacStbbdev         oneapi::tbb::filter<void,short> filter1(oneapi::tbb::filter_mode::serial_out_of_order,
28549e08aacStbbdev                                 [&serial_checker](oneapi::tbb::flow_control&fc)
__anon5895f2ca0b02(oneapi::tbb::flow_control&fc) 28651c0b2f7Stbbdev                                 {
28751c0b2f7Stbbdev                                     auto check_value = ++serial_checker;
28851c0b2f7Stbbdev                                     doWork();
28951c0b2f7Stbbdev                                     CHECK_MESSAGE(check_value == serial_checker, "a serial filter was executed concurrently");
29051c0b2f7Stbbdev                                     if(serial_checker>=(short)max_counter)
29151c0b2f7Stbbdev                                     {
29251c0b2f7Stbbdev                                         fc.stop();
29351c0b2f7Stbbdev                                     }
29451c0b2f7Stbbdev                                     return check_value;
29551c0b2f7Stbbdev                                 });
29651c0b2f7Stbbdev 
2973b045217SAlexei Katranov         short serial_checker2{ 0 };
29849e08aacStbbdev         oneapi::tbb::filter<short, short> filter2(oneapi::tbb::filter_mode::serial_in_order,
29951c0b2f7Stbbdev             [&serial_checker2](int)
__anon5895f2ca0c02(int) 30051c0b2f7Stbbdev             {
30151c0b2f7Stbbdev                 auto check_value = ++serial_checker2;
30251c0b2f7Stbbdev                 doWork();
30351c0b2f7Stbbdev                 CHECK_MESSAGE(check_value == serial_checker2, "a serial filter was executed concurrently");
30451c0b2f7Stbbdev                 return check_value;
30551c0b2f7Stbbdev             });
30651c0b2f7Stbbdev 
30751c0b2f7Stbbdev         utils::SpinBarrier spin_barrier(utils::min(concurrency_level, n_tokens), true);
30849e08aacStbbdev         oneapi::tbb::filter<short,int> filter3(oneapi::tbb::filter_mode::parallel,
30951c0b2f7Stbbdev                                 [&spin_barrier](int value)
__anon5895f2ca0d02(int value) 31051c0b2f7Stbbdev                                 {
31151c0b2f7Stbbdev                                     spin_barrier.wait();
31251c0b2f7Stbbdev                                     doWork();
31351c0b2f7Stbbdev                                     return value;
31451c0b2f7Stbbdev                                 });
31551c0b2f7Stbbdev 
31651c0b2f7Stbbdev 
3173b045217SAlexei Katranov         short order_checker{0};
31849e08aacStbbdev         oneapi::tbb::filter<int,void> filter4(oneapi::tbb::filter_mode::serial_in_order,
31951c0b2f7Stbbdev                                 [&order_checker](int value)
__anon5895f2ca0e02(int value) 32051c0b2f7Stbbdev                                 {
32151c0b2f7Stbbdev                                     CHECK_MESSAGE(++order_checker == value, "the order of message was broken");
32251c0b2f7Stbbdev                                 });
32351c0b2f7Stbbdev 
32449e08aacStbbdev         oneapi::tbb::parallel_pipeline(n_tokens, filter1 & filter2 & filter3 & filter4);
32551c0b2f7Stbbdev     }
32651c0b2f7Stbbdev }
32751c0b2f7Stbbdev 
32851c0b2f7Stbbdev //! Testing max tocken number
32951c0b2f7Stbbdev //! \brief \ref interface \ref requirement
33051c0b2f7Stbbdev TEST_CASE("Testing max token number")
33151c0b2f7Stbbdev {
33251c0b2f7Stbbdev     for(unsigned int i = 1; i < n_tokens; i++)
33351c0b2f7Stbbdev     {
33451c0b2f7Stbbdev         std::atomic<short> active_tokens{0};
33551c0b2f7Stbbdev 
33649e08aacStbbdev         oneapi::tbb::filter<void,int> filter1(oneapi::tbb::filter_mode::parallel,
3373b045217SAlexei Katranov                                 [&active_tokens](oneapi::tbb::flow_control&fc)
__anon5895f2ca0f02(oneapi::tbb::flow_control&fc) 33851c0b2f7Stbbdev                                 {
33951c0b2f7Stbbdev                                     ++active_tokens;
34051c0b2f7Stbbdev                                     doWork();
34151c0b2f7Stbbdev                                     CHECK_MESSAGE(active_tokens <= n_tokens, "max number of tokens is exceed");
34251c0b2f7Stbbdev                                     --active_tokens;
3433b045217SAlexei Katranov                                     if (--input_counter < 0) {
34451c0b2f7Stbbdev                                         fc.stop();
3453b045217SAlexei Katranov                                         input_counter = max_counter;
34651c0b2f7Stbbdev                                     }
34751c0b2f7Stbbdev                                     return 0;
34851c0b2f7Stbbdev                                 });
34951c0b2f7Stbbdev 
35049e08aacStbbdev         oneapi::tbb::filter<int,int> filter2(oneapi::tbb::filter_mode::parallel,
35151c0b2f7Stbbdev                                 [&active_tokens](int value)
__anon5895f2ca1002(int value) 35251c0b2f7Stbbdev                                 {
35351c0b2f7Stbbdev                                     ++active_tokens;
35451c0b2f7Stbbdev                                     doWork();
35551c0b2f7Stbbdev                                     CHECK_MESSAGE(active_tokens <= n_tokens, "max number of tockens is exceed");
35651c0b2f7Stbbdev                                     --active_tokens;
35751c0b2f7Stbbdev                                     return value;
35851c0b2f7Stbbdev                                 });
35951c0b2f7Stbbdev 
36049e08aacStbbdev         oneapi::tbb::filter<int,void> filter3(oneapi::tbb::filter_mode::serial_out_of_order,
36151c0b2f7Stbbdev                                 [&active_tokens](int)
__anon5895f2ca1102(int) 36251c0b2f7Stbbdev                                 {
36351c0b2f7Stbbdev                                     ++active_tokens;
36451c0b2f7Stbbdev                                     doWork();
36551c0b2f7Stbbdev                                     CHECK_MESSAGE(active_tokens <= n_tokens, "max number of tockens is exceed");
36651c0b2f7Stbbdev                                     --active_tokens;
36751c0b2f7Stbbdev                                 });
36851c0b2f7Stbbdev 
36949e08aacStbbdev         oneapi::tbb::parallel_pipeline(i, filter1 & filter2 & filter3);
37051c0b2f7Stbbdev     }
37151c0b2f7Stbbdev }
37251c0b2f7Stbbdev 
37351c0b2f7Stbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
37451c0b2f7Stbbdev 
375a088cfa0SKonstantin Boyarinov template <typename... T> struct print;
376a088cfa0SKonstantin Boyarinov 
37751c0b2f7Stbbdev //! Testing deduction guides
37851c0b2f7Stbbdev //! \brief \ref interface \ref requirement
37951c0b2f7Stbbdev TEST_CASE_TEMPLATE("Deduction guides testing", T, int, unsigned int, double)
38051c0b2f7Stbbdev {
38151c0b2f7Stbbdev     input_filter<T> i_filter;
382a088cfa0SKonstantin Boyarinov 
38349e08aacStbbdev     oneapi::tbb::filter  fc1(oneapi::tbb::filter_mode::serial_in_order, i_filter);
38449e08aacStbbdev     static_assert(std::is_same_v<decltype(fc1), oneapi::tbb::filter<void, T>>);
38551c0b2f7Stbbdev 
38649e08aacStbbdev     oneapi::tbb::filter fc2 (fc1);
38749e08aacStbbdev     static_assert(std::is_same_v<decltype(fc2), oneapi::tbb::filter<void, T>>);
38851c0b2f7Stbbdev 
38951c0b2f7Stbbdev     middle_filter<T, std::size_t> m_filter;
39049e08aacStbbdev     oneapi::tbb::filter  fc3(oneapi::tbb::filter_mode::serial_in_order, m_filter);
39149e08aacStbbdev     static_assert(std::is_same_v<decltype(fc3), oneapi::tbb::filter<T, std::size_t>>);
39251c0b2f7Stbbdev 
__anon5895f2ca1202(int&&) 39349e08aacStbbdev     oneapi::tbb::filter frv(oneapi::tbb::filter_mode::serial_in_order, [](int&&) -> double { return 0.0; });
__anon5895f2ca1302(const int&) 39449e08aacStbbdev     oneapi::tbb::filter fclv(oneapi::tbb::filter_mode::serial_in_order, [](const int&) -> double { return 0.0; });
__anon5895f2ca1402(const int) 39549e08aacStbbdev     oneapi::tbb::filter fc(oneapi::tbb::filter_mode::serial_in_order, [](const int) -> double { return 0.0; });
39651c0b2f7Stbbdev 
39749e08aacStbbdev     static_assert(std::is_same_v<decltype(frv), oneapi::tbb::filter<int, double>>);
39849e08aacStbbdev     static_assert(std::is_same_v<decltype(fclv), oneapi::tbb::filter<int, double>>);
39949e08aacStbbdev     static_assert(std::is_same_v<decltype(fc), oneapi::tbb::filter<int, double>>);
40051c0b2f7Stbbdev }
40151c0b2f7Stbbdev #endif  //__TBB_CPP17_DEDUCTION_GUIDES_PRESENT
402a088cfa0SKonstantin Boyarinov 
403*d238e987SKonstantin Boyarinov #if __TBB_CPP17_INVOKE_PRESENT
404a088cfa0SKonstantin Boyarinov 
405*d238e987SKonstantin Boyarinov template <typename MiddleFilterBody, typename LastFilterBody>
test_pipeline_invoke_basic(const MiddleFilterBody & middle_body,const LastFilterBody & last_body)406*d238e987SKonstantin Boyarinov void test_pipeline_invoke_basic(const MiddleFilterBody& middle_body, const LastFilterBody& last_body) {
407*d238e987SKonstantin Boyarinov     using output_filter_type = test_invoke::SmartID<std::size_t>;
408*d238e987SKonstantin Boyarinov     using middle_filter_type = test_invoke::SmartID<output_filter_type>;
409a088cfa0SKonstantin Boyarinov 
410*d238e987SKonstantin Boyarinov     const std::size_t input_count = 10;
411*d238e987SKonstantin Boyarinov     std::size_t signal_point = 0;
412*d238e987SKonstantin Boyarinov     std::size_t counter = 0;
413a088cfa0SKonstantin Boyarinov 
414*d238e987SKonstantin Boyarinov     auto first_body = [&](oneapi::tbb::flow_control& fc) -> middle_filter_type {
415*d238e987SKonstantin Boyarinov         if (++counter > input_count) {
416*d238e987SKonstantin Boyarinov             fc.stop();
417*d238e987SKonstantin Boyarinov         }
418*d238e987SKonstantin Boyarinov         return middle_filter_type{output_filter_type{&signal_point}};
419*d238e987SKonstantin Boyarinov     };
420a088cfa0SKonstantin Boyarinov 
421*d238e987SKonstantin Boyarinov     auto first_filter = oneapi::tbb::make_filter<void, middle_filter_type>(oneapi::tbb::filter_mode::serial_in_order, first_body);
422*d238e987SKonstantin Boyarinov     auto middle_filter = oneapi::tbb::make_filter<middle_filter_type, output_filter_type>(oneapi::tbb::filter_mode::serial_in_order, middle_body);
423*d238e987SKonstantin Boyarinov     auto last_filter = oneapi::tbb::make_filter<output_filter_type, void>(oneapi::tbb::filter_mode::serial_in_order, last_body);
424a088cfa0SKonstantin Boyarinov 
425*d238e987SKonstantin Boyarinov     oneapi::tbb::parallel_pipeline(16, first_filter & middle_filter & last_filter);
426a088cfa0SKonstantin Boyarinov 
427*d238e987SKonstantin Boyarinov     CHECK(signal_point == input_count);
428*d238e987SKonstantin Boyarinov }
429a088cfa0SKonstantin Boyarinov 
430*d238e987SKonstantin Boyarinov //! Test that parallel_pipeline uses std::invoke to run the filter body
431*d238e987SKonstantin Boyarinov //! \brief \ref requirement
432*d238e987SKonstantin Boyarinov TEST_CASE("parallel_pipeline and std::invoke") {
433*d238e987SKonstantin Boyarinov     using output_filter_type = test_invoke::SmartID<std::size_t>;
434*d238e987SKonstantin Boyarinov     using middle_filter_type = test_invoke::SmartID<output_filter_type>;
435a088cfa0SKonstantin Boyarinov 
436*d238e987SKonstantin Boyarinov     test_pipeline_invoke_basic(&middle_filter_type::get_id, &output_filter_type::operate); // Pointer to non-static function as middle filter
437*d238e987SKonstantin Boyarinov     test_pipeline_invoke_basic(&middle_filter_type::id, &output_filter_type::operate); // Pointer to non-static member as middle filter
438*d238e987SKonstantin Boyarinov }
439a088cfa0SKonstantin Boyarinov 
440*d238e987SKonstantin Boyarinov #endif // __TBB_CPP17_INVOKE_PRESENT
441