xref: /oneTBB/test/tbb/test_buffer_node.cpp (revision b15aabb3)
151c0b2f7Stbbdev /*
2*b15aabb3Stbbdev     Copyright (c) 2005-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 #include "common/config.h"
1851c0b2f7Stbbdev 
1951c0b2f7Stbbdev // TODO revamp: move parts dependent on __TBB_EXTRA_DEBUG into separate test(s) since having these
2051c0b2f7Stbbdev // parts in all of tests might make testing of the product, which is different from what is actually
2151c0b2f7Stbbdev // released.
2251c0b2f7Stbbdev #define __TBB_EXTRA_DEBUG 1
2351c0b2f7Stbbdev #include "tbb/flow_graph.h"
2451c0b2f7Stbbdev 
2551c0b2f7Stbbdev #include "common/test.h"
2651c0b2f7Stbbdev #include "common/utils.h"
2751c0b2f7Stbbdev #include "common/graph_utils.h"
2851c0b2f7Stbbdev #include "common/test_follows_and_precedes_api.h"
2951c0b2f7Stbbdev 
3051c0b2f7Stbbdev 
3151c0b2f7Stbbdev //! \file test_buffer_node.cpp
3251c0b2f7Stbbdev //! \brief Test for [flow_graph.buffer_node] specification
3351c0b2f7Stbbdev 
3451c0b2f7Stbbdev 
3551c0b2f7Stbbdev #define N 1000
3651c0b2f7Stbbdev #define C 10
3751c0b2f7Stbbdev 
3851c0b2f7Stbbdev template< typename T >
3951c0b2f7Stbbdev void spin_try_get( tbb::flow::buffer_node<T> &b, T &value ) {
4051c0b2f7Stbbdev     while ( b.try_get(value) != true ) {}
4151c0b2f7Stbbdev }
4251c0b2f7Stbbdev 
4351c0b2f7Stbbdev template< typename T >
4451c0b2f7Stbbdev void check_item( T* count_value, T &value ) {
4551c0b2f7Stbbdev     count_value[value / N] += value % N;
4651c0b2f7Stbbdev }
4751c0b2f7Stbbdev 
4851c0b2f7Stbbdev template< typename T >
4951c0b2f7Stbbdev struct parallel_puts : utils::NoAssign {
5051c0b2f7Stbbdev 
5151c0b2f7Stbbdev     tbb::flow::buffer_node<T> &my_b;
5251c0b2f7Stbbdev 
5351c0b2f7Stbbdev     parallel_puts( tbb::flow::buffer_node<T> &b ) : my_b(b) {}
5451c0b2f7Stbbdev 
5551c0b2f7Stbbdev     void operator()(int i) const {
5651c0b2f7Stbbdev         for (int j = 0; j < N; ++j) {
5751c0b2f7Stbbdev             bool msg = my_b.try_put( T(N*i + j) );
5851c0b2f7Stbbdev             CHECK_MESSAGE( msg == true, "" );
5951c0b2f7Stbbdev         }
6051c0b2f7Stbbdev     }
6151c0b2f7Stbbdev };
6251c0b2f7Stbbdev 
6351c0b2f7Stbbdev template< typename T >
6451c0b2f7Stbbdev struct touches {
6551c0b2f7Stbbdev 
6651c0b2f7Stbbdev     bool **my_touches;
6751c0b2f7Stbbdev     int my_num_threads;
6851c0b2f7Stbbdev 
6951c0b2f7Stbbdev     touches( int num_threads ) : my_num_threads(num_threads) {
7051c0b2f7Stbbdev         my_touches = new bool* [my_num_threads];
7151c0b2f7Stbbdev         for ( int p = 0; p < my_num_threads; ++p) {
7251c0b2f7Stbbdev             my_touches[p] = new bool[N];
7351c0b2f7Stbbdev             for ( int n = 0; n < N; ++n)
7451c0b2f7Stbbdev                 my_touches[p][n] = false;
7551c0b2f7Stbbdev         }
7651c0b2f7Stbbdev     }
7751c0b2f7Stbbdev 
7851c0b2f7Stbbdev     ~touches() {
7951c0b2f7Stbbdev         for ( int p = 0; p < my_num_threads; ++p) {
8051c0b2f7Stbbdev             delete [] my_touches[p];
8151c0b2f7Stbbdev         }
8251c0b2f7Stbbdev         delete [] my_touches;
8351c0b2f7Stbbdev     }
8451c0b2f7Stbbdev 
8551c0b2f7Stbbdev     bool check( T v ) {
8651c0b2f7Stbbdev         CHECK_MESSAGE( my_touches[v/N][v%N] == false, "" );
8751c0b2f7Stbbdev         my_touches[v/N][v%N] = true;
8851c0b2f7Stbbdev         return true;
8951c0b2f7Stbbdev     }
9051c0b2f7Stbbdev 
9151c0b2f7Stbbdev     bool validate_touches() {
9251c0b2f7Stbbdev         for ( int p = 0; p < my_num_threads; ++p) {
9351c0b2f7Stbbdev             for ( int n = 0; n < N; ++n) {
9451c0b2f7Stbbdev                 CHECK_MESSAGE( my_touches[p][n] == true, "" );
9551c0b2f7Stbbdev             }
9651c0b2f7Stbbdev         }
9751c0b2f7Stbbdev         return true;
9851c0b2f7Stbbdev     }
9951c0b2f7Stbbdev };
10051c0b2f7Stbbdev 
10151c0b2f7Stbbdev template< typename T >
10251c0b2f7Stbbdev struct parallel_gets : utils::NoAssign {
10351c0b2f7Stbbdev 
10451c0b2f7Stbbdev     tbb::flow::buffer_node<T> &my_b;
10551c0b2f7Stbbdev     touches<T> &my_touches;
10651c0b2f7Stbbdev 
10751c0b2f7Stbbdev     parallel_gets( tbb::flow::buffer_node<T> &b, touches<T> &t) : my_b(b), my_touches(t) {}
10851c0b2f7Stbbdev 
10951c0b2f7Stbbdev     void operator()(int) const {
11051c0b2f7Stbbdev         for (int j = 0; j < N; ++j) {
11151c0b2f7Stbbdev             T v;
11251c0b2f7Stbbdev             spin_try_get( my_b, v );
11351c0b2f7Stbbdev             my_touches.check( v );
11451c0b2f7Stbbdev         }
11551c0b2f7Stbbdev     }
11651c0b2f7Stbbdev 
11751c0b2f7Stbbdev };
11851c0b2f7Stbbdev 
11951c0b2f7Stbbdev template< typename T >
12051c0b2f7Stbbdev struct parallel_put_get : utils::NoAssign {
12151c0b2f7Stbbdev 
12251c0b2f7Stbbdev     tbb::flow::buffer_node<T> &my_b;
12351c0b2f7Stbbdev     touches<T> &my_touches;
12451c0b2f7Stbbdev 
12551c0b2f7Stbbdev     parallel_put_get( tbb::flow::buffer_node<T> &b, touches<T> &t ) : my_b(b), my_touches(t) {}
12651c0b2f7Stbbdev 
12751c0b2f7Stbbdev     void operator()(int tid) const {
12851c0b2f7Stbbdev 
12951c0b2f7Stbbdev         for ( int i = 0; i < N; i+=C ) {
13051c0b2f7Stbbdev             int j_end = ( N < i + C ) ? N : i + C;
13151c0b2f7Stbbdev             // dump about C values into the buffer
13251c0b2f7Stbbdev             for ( int j = i; j < j_end; ++j ) {
13351c0b2f7Stbbdev                 CHECK_MESSAGE( my_b.try_put( T (N*tid + j ) ) == true, "" );
13451c0b2f7Stbbdev             }
13551c0b2f7Stbbdev             // receiver about C values from the buffer
13651c0b2f7Stbbdev             for ( int j = i; j < j_end; ++j ) {
13751c0b2f7Stbbdev                 T v;
13851c0b2f7Stbbdev                 spin_try_get( my_b, v );
13951c0b2f7Stbbdev                 my_touches.check( v );
14051c0b2f7Stbbdev             }
14151c0b2f7Stbbdev         }
14251c0b2f7Stbbdev     }
14351c0b2f7Stbbdev 
14451c0b2f7Stbbdev };
14551c0b2f7Stbbdev 
14651c0b2f7Stbbdev //
14751c0b2f7Stbbdev // Tests
14851c0b2f7Stbbdev //
14951c0b2f7Stbbdev // Item can be reserved, released, consumed ( single serial receiver )
15051c0b2f7Stbbdev //
15151c0b2f7Stbbdev template< typename T >
15251c0b2f7Stbbdev int test_reservation() {
15351c0b2f7Stbbdev     tbb::flow::graph g;
15451c0b2f7Stbbdev     T bogus_value(-1);
15551c0b2f7Stbbdev 
15651c0b2f7Stbbdev     // Simple tests
15751c0b2f7Stbbdev     tbb::flow::buffer_node<T> b(g);
15851c0b2f7Stbbdev 
15951c0b2f7Stbbdev     b.try_put(T(1));
16051c0b2f7Stbbdev     b.try_put(T(2));
16151c0b2f7Stbbdev     b.try_put(T(3));
16251c0b2f7Stbbdev 
16351c0b2f7Stbbdev     T v, vsum;
16451c0b2f7Stbbdev     CHECK_MESSAGE( b.try_reserve(v) == true, "" );
16551c0b2f7Stbbdev     CHECK_MESSAGE( b.try_release() == true, "" );
16651c0b2f7Stbbdev     v = bogus_value;
16751c0b2f7Stbbdev     g.wait_for_all();
16851c0b2f7Stbbdev     CHECK_MESSAGE( b.try_reserve(v) == true, "" );
16951c0b2f7Stbbdev     CHECK_MESSAGE( b.try_consume() == true, "" );
17051c0b2f7Stbbdev     vsum += v;
17151c0b2f7Stbbdev     v = bogus_value;
17251c0b2f7Stbbdev     g.wait_for_all();
17351c0b2f7Stbbdev 
17451c0b2f7Stbbdev     CHECK_MESSAGE( b.try_get(v) == true, "" );
17551c0b2f7Stbbdev     vsum += v;
17651c0b2f7Stbbdev     v = bogus_value;
17751c0b2f7Stbbdev     g.wait_for_all();
17851c0b2f7Stbbdev 
17951c0b2f7Stbbdev     CHECK_MESSAGE( b.try_reserve(v) == true, "" );
18051c0b2f7Stbbdev     CHECK_MESSAGE( b.try_release() == true, "" );
18151c0b2f7Stbbdev     v = bogus_value;
18251c0b2f7Stbbdev     g.wait_for_all();
18351c0b2f7Stbbdev     CHECK_MESSAGE( b.try_reserve(v) == true, "" );
18451c0b2f7Stbbdev     CHECK_MESSAGE( b.try_consume() == true, "" );
18551c0b2f7Stbbdev     vsum += v;
18651c0b2f7Stbbdev     CHECK_MESSAGE( vsum == T(6), "");
18751c0b2f7Stbbdev     v = bogus_value;
18851c0b2f7Stbbdev     g.wait_for_all();
18951c0b2f7Stbbdev 
19051c0b2f7Stbbdev     return 0;
19151c0b2f7Stbbdev }
19251c0b2f7Stbbdev 
19351c0b2f7Stbbdev //
19451c0b2f7Stbbdev // Tests
19551c0b2f7Stbbdev //
19651c0b2f7Stbbdev // multiple parallel senders, items in arbitrary order
19751c0b2f7Stbbdev // multiple parallel senders, multiple parallel receivers, items in arbitrary order and all items received
19851c0b2f7Stbbdev //   * overlapped puts / gets
19951c0b2f7Stbbdev //   * all puts finished before any getS
20051c0b2f7Stbbdev //
20151c0b2f7Stbbdev template< typename T >
20251c0b2f7Stbbdev int test_parallel(int num_threads) {
20351c0b2f7Stbbdev     tbb::flow::graph g;
20451c0b2f7Stbbdev     tbb::flow::buffer_node<T> b(g);
20551c0b2f7Stbbdev     tbb::flow::buffer_node<T> b2(g);
20651c0b2f7Stbbdev     tbb::flow::buffer_node<T> b3(g);
20751c0b2f7Stbbdev     T bogus_value(-1);
20851c0b2f7Stbbdev     T j = bogus_value;
20951c0b2f7Stbbdev 
21051c0b2f7Stbbdev     NativeParallelFor( num_threads, parallel_puts<T>(b) );
21151c0b2f7Stbbdev 
21251c0b2f7Stbbdev     T *next_value = new T[num_threads];
21351c0b2f7Stbbdev     for (int tid = 0; tid < num_threads; ++tid) next_value[tid] = T(0);
21451c0b2f7Stbbdev 
21551c0b2f7Stbbdev     for (int i = 0; i < num_threads * N; ++i ) {
21651c0b2f7Stbbdev         spin_try_get( b, j );
21751c0b2f7Stbbdev         check_item( next_value, j );
21851c0b2f7Stbbdev         j = bogus_value;
21951c0b2f7Stbbdev     }
22051c0b2f7Stbbdev     for (int tid = 0; tid < num_threads; ++tid)  {
22151c0b2f7Stbbdev         CHECK_MESSAGE( next_value[tid] == T((N*(N-1))/2), "" );
22251c0b2f7Stbbdev     }
22351c0b2f7Stbbdev 
22451c0b2f7Stbbdev     j = bogus_value;
22551c0b2f7Stbbdev     g.wait_for_all();
22651c0b2f7Stbbdev     CHECK_MESSAGE( b.try_get( j ) == false, "" );
22751c0b2f7Stbbdev     CHECK_MESSAGE( j == bogus_value, "" );
22851c0b2f7Stbbdev 
22951c0b2f7Stbbdev     NativeParallelFor( num_threads, parallel_puts<T>(b) );
23051c0b2f7Stbbdev 
23151c0b2f7Stbbdev     {
23251c0b2f7Stbbdev         touches< T > t( num_threads );
23351c0b2f7Stbbdev         NativeParallelFor( num_threads, parallel_gets<T>(b, t) );
23451c0b2f7Stbbdev         g.wait_for_all();
23551c0b2f7Stbbdev         CHECK_MESSAGE( t.validate_touches(), "" );
23651c0b2f7Stbbdev     }
23751c0b2f7Stbbdev     j = bogus_value;
23851c0b2f7Stbbdev     CHECK_MESSAGE( b.try_get( j ) == false, "" );
23951c0b2f7Stbbdev     CHECK_MESSAGE( j == bogus_value, "" );
24051c0b2f7Stbbdev 
24151c0b2f7Stbbdev     g.wait_for_all();
24251c0b2f7Stbbdev     {
24351c0b2f7Stbbdev         touches< T > t( num_threads );
24451c0b2f7Stbbdev         NativeParallelFor( num_threads, parallel_put_get<T>(b, t) );
24551c0b2f7Stbbdev         g.wait_for_all();
24651c0b2f7Stbbdev         CHECK_MESSAGE( t.validate_touches(), "" );
24751c0b2f7Stbbdev     }
24851c0b2f7Stbbdev     j = bogus_value;
24951c0b2f7Stbbdev     CHECK_MESSAGE( b.try_get( j ) == false, "" );
25051c0b2f7Stbbdev     CHECK_MESSAGE( j == bogus_value, "" );
25151c0b2f7Stbbdev 
25251c0b2f7Stbbdev     tbb::flow::make_edge( b, b2 );
25351c0b2f7Stbbdev     tbb::flow::make_edge( b2, b3 );
25451c0b2f7Stbbdev 
25551c0b2f7Stbbdev     NativeParallelFor( num_threads, parallel_puts<T>(b) );
25651c0b2f7Stbbdev     {
25751c0b2f7Stbbdev         touches< T > t( num_threads );
25851c0b2f7Stbbdev         NativeParallelFor( num_threads, parallel_gets<T>(b3, t) );
25951c0b2f7Stbbdev         g.wait_for_all();
26051c0b2f7Stbbdev         CHECK_MESSAGE( t.validate_touches(), "" );
26151c0b2f7Stbbdev     }
26251c0b2f7Stbbdev     j = bogus_value;
26351c0b2f7Stbbdev     g.wait_for_all();
26451c0b2f7Stbbdev     CHECK_MESSAGE( b.try_get( j ) == false, "" );
26551c0b2f7Stbbdev     g.wait_for_all();
26651c0b2f7Stbbdev     CHECK_MESSAGE( b2.try_get( j ) == false, "" );
26751c0b2f7Stbbdev     g.wait_for_all();
26851c0b2f7Stbbdev     CHECK_MESSAGE( b3.try_get( j ) == false, "" );
26951c0b2f7Stbbdev     CHECK_MESSAGE( j == bogus_value, "" );
27051c0b2f7Stbbdev 
27151c0b2f7Stbbdev     // test copy constructor
27251c0b2f7Stbbdev     CHECK_MESSAGE( b.remove_successor( b2 ), "" );
27351c0b2f7Stbbdev     // fill up b:
27451c0b2f7Stbbdev     NativeParallelFor( num_threads, parallel_puts<T>(b) );
27551c0b2f7Stbbdev     // copy b:
27651c0b2f7Stbbdev     tbb::flow::buffer_node<T> b_copy(b);
27751c0b2f7Stbbdev 
27851c0b2f7Stbbdev     // b_copy should be empty
27951c0b2f7Stbbdev     j = bogus_value;
28051c0b2f7Stbbdev     g.wait_for_all();
28151c0b2f7Stbbdev     CHECK_MESSAGE( b_copy.try_get( j ) == false, "" );
28251c0b2f7Stbbdev 
28351c0b2f7Stbbdev     // hook them together:
28451c0b2f7Stbbdev     CHECK_MESSAGE( b.register_successor(b_copy) == true, "" );
28551c0b2f7Stbbdev     // try to get content from b_copy
28651c0b2f7Stbbdev     {
28751c0b2f7Stbbdev         touches< T > t( num_threads );
28851c0b2f7Stbbdev         NativeParallelFor( num_threads, parallel_gets<T>(b_copy, t) );
28951c0b2f7Stbbdev         g.wait_for_all();
29051c0b2f7Stbbdev         CHECK_MESSAGE( t.validate_touches(), "" );
29151c0b2f7Stbbdev     }
29251c0b2f7Stbbdev     // now both should be empty
29351c0b2f7Stbbdev     j = bogus_value;
29451c0b2f7Stbbdev     g.wait_for_all();
29551c0b2f7Stbbdev     CHECK_MESSAGE( b.try_get( j ) == false, "" );
29651c0b2f7Stbbdev     g.wait_for_all();
29751c0b2f7Stbbdev     CHECK_MESSAGE( b_copy.try_get( j ) == false, "" );
29851c0b2f7Stbbdev     CHECK_MESSAGE( j == bogus_value, "" );
29951c0b2f7Stbbdev 
30051c0b2f7Stbbdev     delete [] next_value;
30151c0b2f7Stbbdev     return 0;
30251c0b2f7Stbbdev }
30351c0b2f7Stbbdev 
30451c0b2f7Stbbdev //
30551c0b2f7Stbbdev // Tests
30651c0b2f7Stbbdev //
30751c0b2f7Stbbdev // Predecessors cannot be registered
30851c0b2f7Stbbdev // Empty buffer rejects item requests
30951c0b2f7Stbbdev // Single serial sender, items in arbitrary order
31051c0b2f7Stbbdev // Chained buffers ( 2 & 3 ), single sender, items at last buffer in arbitrary order
31151c0b2f7Stbbdev //
31251c0b2f7Stbbdev 
31351c0b2f7Stbbdev #define TBB_INTERNAL_NAMESPACE detail::d1
31451c0b2f7Stbbdev using tbb::TBB_INTERNAL_NAMESPACE::register_predecessor;
31551c0b2f7Stbbdev using tbb::TBB_INTERNAL_NAMESPACE::remove_predecessor;
31651c0b2f7Stbbdev 
31751c0b2f7Stbbdev template< typename T >
31851c0b2f7Stbbdev int test_serial() {
31951c0b2f7Stbbdev     tbb::flow::graph g;
32051c0b2f7Stbbdev     T bogus_value(-1);
32151c0b2f7Stbbdev 
32251c0b2f7Stbbdev     tbb::flow::buffer_node<T> b(g);
32351c0b2f7Stbbdev     tbb::flow::buffer_node<T> b2(g);
32451c0b2f7Stbbdev     T j = bogus_value;
32551c0b2f7Stbbdev 
32651c0b2f7Stbbdev     //
32751c0b2f7Stbbdev     // Rejects attempts to add / remove predecessor
32851c0b2f7Stbbdev     // Rejects request from empty buffer
32951c0b2f7Stbbdev     //
33051c0b2f7Stbbdev     CHECK_MESSAGE( register_predecessor<T>( b, b2 ) == false, "" );
33151c0b2f7Stbbdev     CHECK_MESSAGE( remove_predecessor<T>( b, b2 ) == false, "" );
33251c0b2f7Stbbdev     CHECK_MESSAGE( b.try_get( j ) == false, "" );
33351c0b2f7Stbbdev     CHECK_MESSAGE( j == bogus_value, "" );
33451c0b2f7Stbbdev 
33551c0b2f7Stbbdev     //
33651c0b2f7Stbbdev     // Simple puts and gets
33751c0b2f7Stbbdev     //
33851c0b2f7Stbbdev 
33951c0b2f7Stbbdev     for (int i = 0; i < N; ++i) {
34051c0b2f7Stbbdev         bool msg = b.try_put( T(i) );
34151c0b2f7Stbbdev         CHECK_MESSAGE( msg == true, "" );
34251c0b2f7Stbbdev     }
34351c0b2f7Stbbdev 
34451c0b2f7Stbbdev     T vsum = T(0);
34551c0b2f7Stbbdev     for (int i = 0; i < N; ++i) {
34651c0b2f7Stbbdev         j = bogus_value;
34751c0b2f7Stbbdev         spin_try_get( b, j );
34851c0b2f7Stbbdev         vsum += j;
34951c0b2f7Stbbdev     }
35051c0b2f7Stbbdev     CHECK_MESSAGE( vsum == (N*(N-1))/2, "");
35151c0b2f7Stbbdev     j = bogus_value;
35251c0b2f7Stbbdev     g.wait_for_all();
35351c0b2f7Stbbdev     CHECK_MESSAGE( b.try_get( j ) == false, "" );
35451c0b2f7Stbbdev     CHECK_MESSAGE( j == bogus_value, "" );
35551c0b2f7Stbbdev 
35651c0b2f7Stbbdev     tbb::flow::make_edge(b, b2);
35751c0b2f7Stbbdev 
35851c0b2f7Stbbdev     vsum = T(0);
35951c0b2f7Stbbdev     for (int i = 0; i < N; ++i) {
36051c0b2f7Stbbdev         bool msg = b.try_put( T(i) );
36151c0b2f7Stbbdev         CHECK_MESSAGE( msg == true, "" );
36251c0b2f7Stbbdev     }
36351c0b2f7Stbbdev 
36451c0b2f7Stbbdev     for (int i = 0; i < N; ++i) {
36551c0b2f7Stbbdev         j = bogus_value;
36651c0b2f7Stbbdev         spin_try_get( b2, j );
36751c0b2f7Stbbdev         vsum += j;
36851c0b2f7Stbbdev     }
36951c0b2f7Stbbdev     CHECK_MESSAGE( vsum == (N*(N-1))/2, "");
37051c0b2f7Stbbdev     j = bogus_value;
37151c0b2f7Stbbdev     g.wait_for_all();
37251c0b2f7Stbbdev     CHECK_MESSAGE( b.try_get( j ) == false, "" );
37351c0b2f7Stbbdev     g.wait_for_all();
37451c0b2f7Stbbdev     CHECK_MESSAGE( b2.try_get( j ) == false, "" );
37551c0b2f7Stbbdev     CHECK_MESSAGE( j == bogus_value, "" );
37651c0b2f7Stbbdev 
37751c0b2f7Stbbdev     tbb::flow::remove_edge(b, b2);
37851c0b2f7Stbbdev     CHECK_MESSAGE( b.try_put( 1 ) == true, "" );
37951c0b2f7Stbbdev     g.wait_for_all();
38051c0b2f7Stbbdev     CHECK_MESSAGE( b2.try_get( j ) == false, "" );
38151c0b2f7Stbbdev     CHECK_MESSAGE( j == bogus_value, "" );
38251c0b2f7Stbbdev     g.wait_for_all();
38351c0b2f7Stbbdev     CHECK_MESSAGE( b.try_get( j ) == true, "" );
38451c0b2f7Stbbdev     CHECK_MESSAGE( j == 1, "" );
38551c0b2f7Stbbdev 
38651c0b2f7Stbbdev     tbb::flow::buffer_node<T> b3(g);
38751c0b2f7Stbbdev     tbb::flow::make_edge( b, b2 );
38851c0b2f7Stbbdev     tbb::flow::make_edge( b2, b3 );
38951c0b2f7Stbbdev 
39051c0b2f7Stbbdev     vsum = T(0);
39151c0b2f7Stbbdev     for (int i = 0; i < N; ++i) {
39251c0b2f7Stbbdev         bool msg = b.try_put( T(i) );
39351c0b2f7Stbbdev         CHECK_MESSAGE( msg == true, "" );
39451c0b2f7Stbbdev     }
39551c0b2f7Stbbdev 
39651c0b2f7Stbbdev     for (int i = 0; i < N; ++i) {
39751c0b2f7Stbbdev         j = bogus_value;
39851c0b2f7Stbbdev         spin_try_get( b3, j );
39951c0b2f7Stbbdev         vsum += j;
40051c0b2f7Stbbdev     }
40151c0b2f7Stbbdev     CHECK_MESSAGE( vsum == (N*(N-1))/2, "");
40251c0b2f7Stbbdev     j = bogus_value;
40351c0b2f7Stbbdev     g.wait_for_all();
40451c0b2f7Stbbdev     CHECK_MESSAGE( b.try_get( j ) == false, "" );
40551c0b2f7Stbbdev     g.wait_for_all();
40651c0b2f7Stbbdev     CHECK_MESSAGE( b2.try_get( j ) == false, "" );
40751c0b2f7Stbbdev     g.wait_for_all();
40851c0b2f7Stbbdev     CHECK_MESSAGE( b3.try_get( j ) == false, "" );
40951c0b2f7Stbbdev     CHECK_MESSAGE( j == bogus_value, "" );
41051c0b2f7Stbbdev 
41151c0b2f7Stbbdev     tbb::flow::remove_edge(b, b2);
41251c0b2f7Stbbdev     CHECK_MESSAGE( b.try_put( 1 ) == true, "" );
41351c0b2f7Stbbdev     g.wait_for_all();
41451c0b2f7Stbbdev     CHECK_MESSAGE( b2.try_get( j ) == false, "" );
41551c0b2f7Stbbdev     CHECK_MESSAGE( j == bogus_value, "" );
41651c0b2f7Stbbdev     g.wait_for_all();
41751c0b2f7Stbbdev     CHECK_MESSAGE( b3.try_get( j ) == false, "" );
41851c0b2f7Stbbdev     CHECK_MESSAGE( j == bogus_value, "" );
41951c0b2f7Stbbdev     g.wait_for_all();
42051c0b2f7Stbbdev     CHECK_MESSAGE( b.try_get( j ) == true, "" );
42151c0b2f7Stbbdev     CHECK_MESSAGE( j == 1, "" );
42251c0b2f7Stbbdev 
42351c0b2f7Stbbdev     return 0;
42451c0b2f7Stbbdev }
42551c0b2f7Stbbdev 
42651c0b2f7Stbbdev #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
42751c0b2f7Stbbdev #include <array>
42851c0b2f7Stbbdev #include <vector>
42951c0b2f7Stbbdev void test_follows_and_precedes_api() {
43051c0b2f7Stbbdev     using msg_t = tbb::flow::continue_msg;
43151c0b2f7Stbbdev 
43251c0b2f7Stbbdev     std::array<msg_t, 3> messages_for_follows = { {msg_t(), msg_t(), msg_t()} };
43351c0b2f7Stbbdev     std::vector<msg_t> messages_for_precedes = {msg_t(), msg_t(), msg_t()};
43451c0b2f7Stbbdev 
43551c0b2f7Stbbdev     follows_and_precedes_testing::test_follows<msg_t, tbb::flow::buffer_node<msg_t>>(messages_for_follows);
43651c0b2f7Stbbdev     follows_and_precedes_testing::test_precedes<msg_t, tbb::flow::buffer_node<msg_t>>(messages_for_precedes);
43751c0b2f7Stbbdev }
43851c0b2f7Stbbdev #endif
43951c0b2f7Stbbdev 
44051c0b2f7Stbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
44151c0b2f7Stbbdev void test_deduction_guides() {
44251c0b2f7Stbbdev     using namespace tbb::flow;
44351c0b2f7Stbbdev     graph g;
44451c0b2f7Stbbdev     broadcast_node<int> br(g);
44551c0b2f7Stbbdev     buffer_node<int> b0(g);
44651c0b2f7Stbbdev 
44751c0b2f7Stbbdev #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
44851c0b2f7Stbbdev     buffer_node b1(follows(br));
44951c0b2f7Stbbdev     static_assert(std::is_same_v<decltype(b1), buffer_node<int>>);
45051c0b2f7Stbbdev 
45151c0b2f7Stbbdev     buffer_node b2(precedes(br));
45251c0b2f7Stbbdev     static_assert(std::is_same_v<decltype(b2), buffer_node<int>>);
45351c0b2f7Stbbdev #endif
45451c0b2f7Stbbdev 
45551c0b2f7Stbbdev     buffer_node b3(b0);
45651c0b2f7Stbbdev     static_assert(std::is_same_v<decltype(b3), buffer_node<int>>);
45751c0b2f7Stbbdev     g.wait_for_all();
45851c0b2f7Stbbdev }
45951c0b2f7Stbbdev #endif
46051c0b2f7Stbbdev 
46151c0b2f7Stbbdev #include <iomanip>
46251c0b2f7Stbbdev 
46351c0b2f7Stbbdev //! Test buffer_node with parallel and serial neighbours
46451c0b2f7Stbbdev //! \brief \ref requirement \ref error_guessing
46551c0b2f7Stbbdev TEST_CASE("Serial and parallel test"){
46651c0b2f7Stbbdev     for (int p = 2; p <= 4; ++p) {
46751c0b2f7Stbbdev         tbb::task_arena arena(p);
46851c0b2f7Stbbdev         arena.execute(
46951c0b2f7Stbbdev             [&]() {
47051c0b2f7Stbbdev                 test_serial<int>();
47151c0b2f7Stbbdev                 test_parallel<int>(p);
47251c0b2f7Stbbdev             }
47351c0b2f7Stbbdev         );
47451c0b2f7Stbbdev     }
47551c0b2f7Stbbdev }
47651c0b2f7Stbbdev 
47751c0b2f7Stbbdev //! Test reset and cancellation behavior
47851c0b2f7Stbbdev //! \brief \ref error_guessing
47951c0b2f7Stbbdev TEST_CASE("Resets"){
48051c0b2f7Stbbdev     test_resets<int,tbb::flow::buffer_node<int> >();
48151c0b2f7Stbbdev     test_resets<float,tbb::flow::buffer_node<float> >();
48251c0b2f7Stbbdev }
48351c0b2f7Stbbdev 
48451c0b2f7Stbbdev #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
48551c0b2f7Stbbdev //! Test deprecated follows and preceedes API
48651c0b2f7Stbbdev //! \brief \ref error_guessing
48751c0b2f7Stbbdev TEST_CASE("Follows and precedes API"){
48851c0b2f7Stbbdev     test_follows_and_precedes_api();
48951c0b2f7Stbbdev }
49051c0b2f7Stbbdev #endif
49151c0b2f7Stbbdev 
49251c0b2f7Stbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
49351c0b2f7Stbbdev //! Test deduction guides
49451c0b2f7Stbbdev //! \brief requirement
49551c0b2f7Stbbdev TEST_CASE("Deduction guides"){
49651c0b2f7Stbbdev     test_deduction_guides();
49751c0b2f7Stbbdev }
49851c0b2f7Stbbdev #endif
499