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 
17b15aabb3Stbbdev #if __INTEL_COMPILER && _MSC_VER
18b15aabb3Stbbdev #pragma warning(disable : 2586) // decorated name length exceeded, name was truncated
19b15aabb3Stbbdev #endif
2051c0b2f7Stbbdev 
21*de0109beSIlya Mishin #define SEQUENCER_NODE
2251c0b2f7Stbbdev 
2351c0b2f7Stbbdev #include "conformance_flowgraph.h"
2451c0b2f7Stbbdev 
2551c0b2f7Stbbdev //! \file conformance_sequencer_node.cpp
2651c0b2f7Stbbdev //! \brief Test for [flow_graph.sequencer_node] specification
2751c0b2f7Stbbdev 
2851c0b2f7Stbbdev 
2951c0b2f7Stbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
30*de0109beSIlya Mishin template <typename Body>
31*de0109beSIlya Mishin void test_deduction_guides_common(Body body) {
32*de0109beSIlya Mishin     using namespace tbb::flow;
33*de0109beSIlya Mishin     graph g;
34*de0109beSIlya Mishin     broadcast_node<int> br(g);
35*de0109beSIlya Mishin 
36*de0109beSIlya Mishin     sequencer_node s1(g, body);
37*de0109beSIlya Mishin     static_assert(std::is_same_v<decltype(s1), sequencer_node<int>>);
38*de0109beSIlya Mishin 
39*de0109beSIlya Mishin #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
40*de0109beSIlya Mishin     sequencer_node s2(follows(br), body);
41*de0109beSIlya Mishin     static_assert(std::is_same_v<decltype(s2), sequencer_node<int>>);
42*de0109beSIlya Mishin #endif
43*de0109beSIlya Mishin 
44*de0109beSIlya Mishin     sequencer_node s3(s1);
45*de0109beSIlya Mishin     static_assert(std::is_same_v<decltype(s3), sequencer_node<int>>);
46*de0109beSIlya Mishin }
47*de0109beSIlya Mishin 
48*de0109beSIlya Mishin std::size_t sequencer_body_f(const int&) { return 1; }
49*de0109beSIlya Mishin 
5051c0b2f7Stbbdev void test_deduction_guides() {
51*de0109beSIlya Mishin     test_deduction_guides_common([](const int&)->std::size_t { return 1; });
52*de0109beSIlya Mishin     test_deduction_guides_common([](const int&) mutable ->std::size_t { return 1; });
53*de0109beSIlya Mishin     test_deduction_guides_common(sequencer_body_f);
5451c0b2f7Stbbdev }
5551c0b2f7Stbbdev #endif
5651c0b2f7Stbbdev 
57*de0109beSIlya Mishin //! Test deduction guides
58*de0109beSIlya Mishin //! \brief \ref interface \ref requirement
59*de0109beSIlya Mishin TEST_CASE("Deduction guides"){
60*de0109beSIlya Mishin #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
61*de0109beSIlya Mishin     test_deduction_guides();
62*de0109beSIlya Mishin #endif
6351c0b2f7Stbbdev }
6451c0b2f7Stbbdev 
65*de0109beSIlya Mishin //! Test sequencer_node single_push
66*de0109beSIlya Mishin //! \brief \ref requirement
67*de0109beSIlya Mishin TEST_CASE("sequencer_node single_push"){
68*de0109beSIlya Mishin     conformance::sequencer_functor<int> sequencer;
69*de0109beSIlya Mishin     conformance::test_forwarding_single_push<oneapi::tbb::flow::sequencer_node<int>>(sequencer);
70*de0109beSIlya Mishin }
71*de0109beSIlya Mishin 
72*de0109beSIlya Mishin //! Test function_node buffering
73*de0109beSIlya Mishin //! \brief \ref requirement
74*de0109beSIlya Mishin TEST_CASE("sequencer_node buffering"){
75*de0109beSIlya Mishin     conformance::sequencer_functor<int> sequencer;
76*de0109beSIlya Mishin     conformance::test_buffering<oneapi::tbb::flow::sequencer_node<int>, int>(sequencer);
77*de0109beSIlya Mishin }
78*de0109beSIlya Mishin 
79*de0109beSIlya Mishin //! Constructs an empty sequencer_node that belongs to the same graph g as src.
80*de0109beSIlya Mishin //! Any intermediate state of src, including its links to predecessors and successors, is not copied.
81*de0109beSIlya Mishin //! \brief \ref requirement
82*de0109beSIlya Mishin TEST_CASE("sequencer_node copy constructor"){
83*de0109beSIlya Mishin     conformance::sequencer_functor<int> sequencer;
84*de0109beSIlya Mishin     conformance::test_copy_ctor_for_buffering_nodes<oneapi::tbb::flow::sequencer_node<int>>(sequencer);
85*de0109beSIlya Mishin }
86*de0109beSIlya Mishin 
87*de0109beSIlya Mishin //! Test inheritance relations
88*de0109beSIlya Mishin //! \brief \ref interface
89*de0109beSIlya Mishin TEST_CASE("sequencer_node superclasses"){
90*de0109beSIlya Mishin     conformance::test_inheritance<oneapi::tbb::flow::sequencer_node<int>, int, int>();
91*de0109beSIlya Mishin     conformance::test_inheritance<oneapi::tbb::flow::sequencer_node<void*>, void*, void*>();
92*de0109beSIlya Mishin }
93*de0109beSIlya Mishin 
94*de0109beSIlya Mishin //! Test the sequencer_node rejects duplicate sequencer numbers
95*de0109beSIlya Mishin //! \brief \ref interface
96*de0109beSIlya Mishin TEST_CASE("sequencer_node rejects duplicate"){
9749e08aacStbbdev     oneapi::tbb::flow::graph g;
98*de0109beSIlya Mishin     conformance::sequencer_functor<int> sequencer;
99*de0109beSIlya Mishin 
100*de0109beSIlya Mishin     oneapi::tbb::flow::sequencer_node<int> node(g, sequencer);
101*de0109beSIlya Mishin 
102*de0109beSIlya Mishin     node.try_put(1);
103*de0109beSIlya Mishin 
104*de0109beSIlya Mishin     CHECK_MESSAGE((node.try_put(1) == false), "sequencer_node must rejects duplicate sequencer numbers");
105*de0109beSIlya Mishin     g.wait_for_all();
106*de0109beSIlya Mishin }
107*de0109beSIlya Mishin 
108*de0109beSIlya Mishin //! Test queue_node node `try_put()` and `try_get()`
109*de0109beSIlya Mishin //! \brief \ref requirement
110*de0109beSIlya Mishin TEST_CASE("queue_node methods"){
111*de0109beSIlya Mishin     oneapi::tbb::flow::graph g;
112*de0109beSIlya Mishin     conformance::sequencer_functor<int> sequencer;
11351c0b2f7Stbbdev 
11449e08aacStbbdev     oneapi::tbb::flow::sequencer_node<int> node(g, sequencer);
11551c0b2f7Stbbdev 
11651c0b2f7Stbbdev     node.try_put(1);
11751c0b2f7Stbbdev     node.try_put(0);
11851c0b2f7Stbbdev     node.try_put(1);
11951c0b2f7Stbbdev     g.wait_for_all();
12051c0b2f7Stbbdev 
12151c0b2f7Stbbdev     int tmp = -1;
12251c0b2f7Stbbdev     CHECK_MESSAGE((node.try_get(tmp) == true), "Getting from sequencer should succeed");
12351c0b2f7Stbbdev     CHECK_MESSAGE((tmp == 0), "Received value should be correct");
12451c0b2f7Stbbdev 
12551c0b2f7Stbbdev     tmp = -1;
12651c0b2f7Stbbdev     CHECK_MESSAGE((node.try_get(tmp) == true), "Getting from sequencer should succeed");
12751c0b2f7Stbbdev     CHECK_MESSAGE((tmp == 1), "Received value should be correct");
12851c0b2f7Stbbdev 
12951c0b2f7Stbbdev     tmp = -1;
13051c0b2f7Stbbdev     CHECK_MESSAGE((node.try_get(tmp) == false), "Getting from sequencer should not succeed");
13151c0b2f7Stbbdev }
13251c0b2f7Stbbdev 
133*de0109beSIlya Mishin //! The example demonstrates ordering capabilities of the sequencer_node.
134*de0109beSIlya Mishin //! While being processed in parallel, the data is passed to the successor node in the exact same order it was read.
13551c0b2f7Stbbdev //! \brief \ref requirement
136*de0109beSIlya Mishin TEST_CASE("sequencer_node ordering"){
137*de0109beSIlya Mishin     using namespace oneapi::tbb::flow;
138*de0109beSIlya Mishin     using message = conformance::sequencer_functor<int>::seq_message;
139*de0109beSIlya Mishin     graph g;
140*de0109beSIlya Mishin 
141*de0109beSIlya Mishin     // Due to parallelism the node can push messages to its successors in any order
142*de0109beSIlya Mishin     function_node<message, message> process(g, unlimited, [] (message msg) {
143*de0109beSIlya Mishin         msg.data++;
144*de0109beSIlya Mishin         return msg;
145*de0109beSIlya Mishin     });
146*de0109beSIlya Mishin 
147*de0109beSIlya Mishin     sequencer_node<message> ordering(g, conformance::sequencer_functor<int>());
148*de0109beSIlya Mishin 
149*de0109beSIlya Mishin     std::atomic<std::size_t> counter{0};
150*de0109beSIlya Mishin     function_node<message> writer(g, tbb::flow::serial, [&] (const message& msg) {
151*de0109beSIlya Mishin         CHECK_MESSAGE((msg.id == counter++), "The data is passed to the successor node in the exact same order it was read");
152*de0109beSIlya Mishin     });
153*de0109beSIlya Mishin 
154*de0109beSIlya Mishin     tbb::flow::make_edge(process, ordering);
155*de0109beSIlya Mishin     tbb::flow::make_edge(ordering, writer);
156*de0109beSIlya Mishin 
157*de0109beSIlya Mishin     for (std::size_t i = 0; i < 100; ++i) {
158*de0109beSIlya Mishin         message msg = {i, 0};
159*de0109beSIlya Mishin         process.try_put(msg);
16051c0b2f7Stbbdev     }
16151c0b2f7Stbbdev 
162*de0109beSIlya Mishin     g.wait_for_all();
16351c0b2f7Stbbdev }
164