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