151c0b2f7Stbbdev /*
2b15aabb3Stbbdev     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 
17b15aabb3Stbbdev #if __INTEL_COMPILER && _MSC_VER
18b15aabb3Stbbdev #pragma warning(disable : 2586) // decorated name length exceeded, name was truncated
19b15aabb3Stbbdev #endif
20b15aabb3Stbbdev 
2151c0b2f7Stbbdev #include <common/concurrent_priority_queue_common.h>
2251c0b2f7Stbbdev #include <common/initializer_list_support.h>
2351c0b2f7Stbbdev #include <common/container_move_support.h>
2451c0b2f7Stbbdev #include <common/containers_common.h>
25b15aabb3Stbbdev #include <common/test_comparisons.h>
2651c0b2f7Stbbdev #include <scoped_allocator>
2751c0b2f7Stbbdev 
2851c0b2f7Stbbdev //! \file conformance_concurrent_priority_queue.cpp
2951c0b2f7Stbbdev //! \brief Test for [containers.concurrent_priority_queue] specification
3051c0b2f7Stbbdev 
test_to_vector()3151c0b2f7Stbbdev void test_to_vector() {
3251c0b2f7Stbbdev     using equality_comparison_helpers::toVector;
3351c0b2f7Stbbdev     int array[] = {1, 5, 6, 8, 4, 7};
3449e08aacStbbdev     oneapi::tbb::blocked_range<int*> range = utils::make_blocked_range(array);
3551c0b2f7Stbbdev     std::vector<int> source(range.begin(), range.end());
3651c0b2f7Stbbdev 
3749e08aacStbbdev     oneapi::tbb::concurrent_priority_queue<int> q(source.begin(), source.end());
3851c0b2f7Stbbdev     std::vector<int> from_cpq = toVector(q);
3951c0b2f7Stbbdev 
4051c0b2f7Stbbdev     std::sort(source.begin(), source.end());
4151c0b2f7Stbbdev     REQUIRE_MESSAGE(source == from_cpq, "equality_comparison_helpers::toVector incorrectly copied items from CPQ");
4251c0b2f7Stbbdev }
4351c0b2f7Stbbdev 
test_basic()4451c0b2f7Stbbdev void test_basic() {
4551c0b2f7Stbbdev     const int NUMBER = 10;
4651c0b2f7Stbbdev     utils::FastRandom<> rnd(1234);
4751c0b2f7Stbbdev 
4851c0b2f7Stbbdev     std::vector<int> arrInt;
4951c0b2f7Stbbdev     for (int i = 0; i < NUMBER; ++i)
5051c0b2f7Stbbdev         arrInt.emplace_back(rnd.get());
5151c0b2f7Stbbdev 
5251c0b2f7Stbbdev     type_tester(arrInt); // Test integers
5351c0b2f7Stbbdev }
5451c0b2f7Stbbdev 
test_initializer_list()5551c0b2f7Stbbdev void test_initializer_list() {
5651c0b2f7Stbbdev     using namespace initializer_list_support_tests;
5749e08aacStbbdev     test_initializer_list_support<oneapi::tbb::concurrent_priority_queue<char>>({1, 2, 3, 4, 5});
5849e08aacStbbdev     test_initializer_list_support<oneapi::tbb::concurrent_priority_queue<int>>({});
5951c0b2f7Stbbdev }
6051c0b2f7Stbbdev 
6151c0b2f7Stbbdev struct SpecialMemberCalls {
6251c0b2f7Stbbdev     std::size_t copy_ctor_called_times;
6351c0b2f7Stbbdev     std::size_t move_ctor_called_times;
6451c0b2f7Stbbdev     std::size_t copy_assign_called_times;
6551c0b2f7Stbbdev     std::size_t move_assign_called_times;
6651c0b2f7Stbbdev }; // struct SpecialMemberCalls
6751c0b2f7Stbbdev 
operator ==(const SpecialMemberCalls & lhs,const SpecialMemberCalls & rhs)6851c0b2f7Stbbdev bool operator==( const SpecialMemberCalls& lhs, const SpecialMemberCalls& rhs ) {
6951c0b2f7Stbbdev     return lhs.copy_ctor_called_times == rhs.copy_ctor_called_times &&
7051c0b2f7Stbbdev            lhs.move_ctor_called_times == rhs.move_ctor_called_times &&
7151c0b2f7Stbbdev            lhs.copy_assign_called_times == rhs.copy_assign_called_times &&
7251c0b2f7Stbbdev            lhs.move_assign_called_times == rhs.move_assign_called_times;
7351c0b2f7Stbbdev }
7451c0b2f7Stbbdev 
75b15aabb3Stbbdev template <typename CounterType>
76b15aabb3Stbbdev struct MoveOperationTrackerBase {
77b15aabb3Stbbdev     static CounterType copy_ctor_called_times;
78b15aabb3Stbbdev     static CounterType move_ctor_called_times;
79b15aabb3Stbbdev     static CounterType copy_assign_called_times;
80b15aabb3Stbbdev     static CounterType move_assign_called_times;
8151c0b2f7Stbbdev 
special_member_callsMoveOperationTrackerBase8251c0b2f7Stbbdev     static SpecialMemberCalls special_member_calls() {
8351c0b2f7Stbbdev         return SpecialMemberCalls{copy_ctor_called_times, move_ctor_called_times, copy_assign_called_times, move_assign_called_times};
8451c0b2f7Stbbdev     }
85b15aabb3Stbbdev     static CounterType value_counter;
8651c0b2f7Stbbdev     std::size_t value;
8751c0b2f7Stbbdev 
MoveOperationTrackerBaseMoveOperationTrackerBase88b15aabb3Stbbdev     MoveOperationTrackerBase() : value(++value_counter) {}
MoveOperationTrackerBaseMoveOperationTrackerBase89b15aabb3Stbbdev     explicit MoveOperationTrackerBase( const std::size_t val ) : value(val) {}
~MoveOperationTrackerBaseMoveOperationTrackerBase90b15aabb3Stbbdev     ~MoveOperationTrackerBase() { value = 0; }
9151c0b2f7Stbbdev 
MoveOperationTrackerBaseMoveOperationTrackerBase92b15aabb3Stbbdev     MoveOperationTrackerBase( const MoveOperationTrackerBase& other ) : value(other.value) {
9351c0b2f7Stbbdev         REQUIRE_MESSAGE(other.value, "The object has been moved or destroyed");
9451c0b2f7Stbbdev         ++copy_ctor_called_times;
9551c0b2f7Stbbdev     }
9651c0b2f7Stbbdev 
MoveOperationTrackerBaseMoveOperationTrackerBase97b15aabb3Stbbdev     MoveOperationTrackerBase( MoveOperationTrackerBase&& other ) noexcept : value(other.value) {
9851c0b2f7Stbbdev         REQUIRE_MESSAGE(other.value, "The object has been moved or destroyed");
9951c0b2f7Stbbdev         other.value = 0;
10051c0b2f7Stbbdev         ++move_ctor_called_times;
10151c0b2f7Stbbdev     }
10251c0b2f7Stbbdev 
operator =MoveOperationTrackerBase103b15aabb3Stbbdev     MoveOperationTrackerBase& operator=( const MoveOperationTrackerBase& other ) {
10451c0b2f7Stbbdev         REQUIRE_MESSAGE(other.value, "The object has been moved or destroyed");
10551c0b2f7Stbbdev         value = other.value;
10651c0b2f7Stbbdev         ++copy_assign_called_times;
10751c0b2f7Stbbdev         return *this;
10851c0b2f7Stbbdev     }
10951c0b2f7Stbbdev 
operator =MoveOperationTrackerBase110b15aabb3Stbbdev     MoveOperationTrackerBase& operator=( MoveOperationTrackerBase&& other ) noexcept {
11151c0b2f7Stbbdev         REQUIRE_MESSAGE(other.value, "The object has been moved or destroyed");
11251c0b2f7Stbbdev         value = other.value;
11351c0b2f7Stbbdev         other.value = 0;
11451c0b2f7Stbbdev         ++move_assign_called_times;
11551c0b2f7Stbbdev         return *this;
11651c0b2f7Stbbdev     }
11751c0b2f7Stbbdev 
operator <MoveOperationTrackerBase118b15aabb3Stbbdev     bool operator<( const MoveOperationTrackerBase& other ) const {
11951c0b2f7Stbbdev         REQUIRE_MESSAGE(value, "The object has been moved or destroyed");
12051c0b2f7Stbbdev         REQUIRE_MESSAGE(other.value, "The object has been moved or destroyed");
12151c0b2f7Stbbdev         return value < other.value;
12251c0b2f7Stbbdev     }
123b15aabb3Stbbdev }; // struct MoveOperationTrackerBase
12451c0b2f7Stbbdev 
125b15aabb3Stbbdev template<typename CounterType>
operator ==(const MoveOperationTrackerBase<CounterType> & lhs,const MoveOperationTrackerBase<CounterType> & rhs)126b15aabb3Stbbdev bool operator==( const MoveOperationTrackerBase<CounterType>& lhs, const MoveOperationTrackerBase<CounterType>& rhs ) {
12751c0b2f7Stbbdev     return !(lhs < rhs) && !(rhs < lhs);
12851c0b2f7Stbbdev }
12951c0b2f7Stbbdev 
130b15aabb3Stbbdev using MoveOperationTracker = MoveOperationTrackerBase<std::size_t>;
131b15aabb3Stbbdev using MoveOperationTrackerConc = MoveOperationTrackerBase<std::atomic<std::size_t>>;
132b15aabb3Stbbdev 
133b15aabb3Stbbdev template <typename CounterType> CounterType MoveOperationTrackerBase<CounterType>::copy_ctor_called_times(0);
134b15aabb3Stbbdev template <typename CounterType> CounterType MoveOperationTrackerBase<CounterType>::move_ctor_called_times(0);
135b15aabb3Stbbdev template <typename CounterType> CounterType MoveOperationTrackerBase<CounterType>::copy_assign_called_times(0);
136b15aabb3Stbbdev template <typename CounterType> CounterType MoveOperationTrackerBase<CounterType>::move_assign_called_times(0);
137b15aabb3Stbbdev template <typename CounterType> CounterType MoveOperationTrackerBase<CounterType>::value_counter(0);
13851c0b2f7Stbbdev 
13951c0b2f7Stbbdev template <typename Allocator = std::allocator<MoveOperationTracker>>
14051c0b2f7Stbbdev struct CPQSrcFixture {
14151c0b2f7Stbbdev     CPQSrcFixture& operator=( const CPQSrcFixture& ) = delete;
14251c0b2f7Stbbdev 
14351c0b2f7Stbbdev     enum {default_container_size = 100};
14451c0b2f7Stbbdev     using cpq_compare_type = std::less<MoveOperationTracker>;
14551c0b2f7Stbbdev     using cpq_allocator_type = typename std::allocator_traits<Allocator>::template rebind_alloc<MoveOperationTracker>;
14649e08aacStbbdev     using cpq_type = oneapi::tbb::concurrent_priority_queue<MoveOperationTracker, cpq_compare_type, cpq_allocator_type>;
14751c0b2f7Stbbdev 
14851c0b2f7Stbbdev     cpq_type cpq_src;
14951c0b2f7Stbbdev     const std::size_t container_size;
15051c0b2f7Stbbdev 
initCPQSrcFixture15151c0b2f7Stbbdev     void init() {
15251c0b2f7Stbbdev         std::size_t& mcct = MoveOperationTracker::move_ctor_called_times;
15351c0b2f7Stbbdev         std::size_t& ccct = MoveOperationTracker::copy_ctor_called_times;
15451c0b2f7Stbbdev         std::size_t& cact = MoveOperationTracker::copy_assign_called_times;
15551c0b2f7Stbbdev         std::size_t& mact = MoveOperationTracker::move_assign_called_times;
15651c0b2f7Stbbdev         mcct = ccct = cact = mact = 0;
15751c0b2f7Stbbdev 
15851c0b2f7Stbbdev         for (std::size_t i = 1; i <= container_size; ++i) {
15951c0b2f7Stbbdev             cpq_src.push(MoveOperationTracker(i));
16051c0b2f7Stbbdev         }
16151c0b2f7Stbbdev         REQUIRE_MESSAGE(cpq_src.size() == container_size, "Error in test setup");
16251c0b2f7Stbbdev     }
16351c0b2f7Stbbdev 
CPQSrcFixtureCPQSrcFixture16451c0b2f7Stbbdev     CPQSrcFixture( std::size_t size = default_container_size )
16551c0b2f7Stbbdev         : CPQSrcFixture(typename cpq_type::allocator_type(), size) {}
16651c0b2f7Stbbdev 
CPQSrcFixtureCPQSrcFixture16751c0b2f7Stbbdev     CPQSrcFixture( const typename cpq_type::allocator_type& a, std::size_t size = default_container_size )
16851c0b2f7Stbbdev         : cpq_src(a), container_size(size)
16951c0b2f7Stbbdev     {
17051c0b2f7Stbbdev         init();
17151c0b2f7Stbbdev     }
17251c0b2f7Stbbdev }; // struct CPQSrcFixture
17351c0b2f7Stbbdev 
test_steal_move_ctor()17451c0b2f7Stbbdev void test_steal_move_ctor() {
17551c0b2f7Stbbdev     using fixture_type = CPQSrcFixture<>;
17651c0b2f7Stbbdev     using container_type = typename fixture_type::cpq_type;
17751c0b2f7Stbbdev     fixture_type fixture;
17851c0b2f7Stbbdev     container_type src_copy{fixture.cpq_src};
17951c0b2f7Stbbdev 
18051c0b2f7Stbbdev     SpecialMemberCalls previous = MoveOperationTracker::special_member_calls();
18151c0b2f7Stbbdev     container_type dst{std::move(fixture.cpq_src)};
18251c0b2f7Stbbdev     REQUIRE_MESSAGE(previous == MoveOperationTracker::special_member_calls(), "Steal move ctor should not create any new elements");
18351c0b2f7Stbbdev     REQUIRE_MESSAGE(dst == src_copy, "cpq content changed during steal move");
18451c0b2f7Stbbdev     REQUIRE_MESSAGE(!(dst != src_copy), "cpq content changed during steal move");
18551c0b2f7Stbbdev }
18651c0b2f7Stbbdev 
test_steal_move_ctor_with_allocator()18751c0b2f7Stbbdev void test_steal_move_ctor_with_allocator() {
18851c0b2f7Stbbdev     using arena_fixture_type = move_support_tests::TwoMemoryArenasFixture<MoveOperationTracker>;
18951c0b2f7Stbbdev     using fixture_type = CPQSrcFixture<arena_fixture_type::allocator_type>;
19051c0b2f7Stbbdev 
19151c0b2f7Stbbdev     arena_fixture_type arena_fixture(8 * fixture_type::default_container_size);
19251c0b2f7Stbbdev     fixture_type fixture(arena_fixture.source_allocator);
19351c0b2f7Stbbdev     fixture_type::cpq_type src_copy(fixture.cpq_src);
19451c0b2f7Stbbdev 
19551c0b2f7Stbbdev     SpecialMemberCalls previous = MoveOperationTracker::special_member_calls();
19651c0b2f7Stbbdev     fixture_type::cpq_type dst(std::move(fixture.cpq_src), arena_fixture.source_allocator);
19751c0b2f7Stbbdev     REQUIRE_MESSAGE(previous == MoveOperationTracker::special_member_calls(), "Steal move ctor should not create any new elements");
19851c0b2f7Stbbdev     REQUIRE_MESSAGE(dst == src_copy, "cpq content changed during steal move");
19951c0b2f7Stbbdev     REQUIRE_MESSAGE(!(dst != src_copy), "cpq content changed during steal move");
20051c0b2f7Stbbdev }
20151c0b2f7Stbbdev 
test_per_element_move_ctor_with_allocator()20251c0b2f7Stbbdev void test_per_element_move_ctor_with_allocator() {
20351c0b2f7Stbbdev     using arena_fixture_type = move_support_tests::TwoMemoryArenasFixture<MoveOperationTracker>;
20451c0b2f7Stbbdev     using fixture_type = CPQSrcFixture<arena_fixture_type::allocator_type>;
20551c0b2f7Stbbdev 
20651c0b2f7Stbbdev     arena_fixture_type arena_fixture(8 * fixture_type::default_container_size);
20751c0b2f7Stbbdev     fixture_type fixture(arena_fixture.source_allocator);
20851c0b2f7Stbbdev     fixture_type::cpq_type src_copy(fixture.cpq_src);
20951c0b2f7Stbbdev 
21051c0b2f7Stbbdev     SpecialMemberCalls move_ctor_called_cpq_size_times = MoveOperationTracker::special_member_calls();
21151c0b2f7Stbbdev     move_ctor_called_cpq_size_times.move_ctor_called_times += fixture.container_size;
21251c0b2f7Stbbdev 
21351c0b2f7Stbbdev     fixture_type::cpq_type dst(std::move(fixture.cpq_src), arena_fixture.dst_allocator);
21451c0b2f7Stbbdev     REQUIRE_MESSAGE(move_ctor_called_cpq_size_times == MoveOperationTracker::special_member_calls(),
21551c0b2f7Stbbdev                     "Per element move ctor should move initialize all new elements");
21651c0b2f7Stbbdev     REQUIRE_MESSAGE(dst == src_copy, "cpq content changed during move");
21751c0b2f7Stbbdev     REQUIRE_MESSAGE(!(dst != src_copy), "cpq content changed during move");
21851c0b2f7Stbbdev }
21951c0b2f7Stbbdev 
test_steal_move_assign_operator()22051c0b2f7Stbbdev void test_steal_move_assign_operator() {
22151c0b2f7Stbbdev     using fixture_type = CPQSrcFixture<>;
22251c0b2f7Stbbdev 
22351c0b2f7Stbbdev     fixture_type fixture;
22451c0b2f7Stbbdev     fixture_type::cpq_type src_copy(fixture.cpq_src);
22551c0b2f7Stbbdev 
22651c0b2f7Stbbdev     fixture_type::cpq_type dst;
22751c0b2f7Stbbdev     SpecialMemberCalls previous = MoveOperationTracker::special_member_calls();
22851c0b2f7Stbbdev     dst = std::move(fixture.cpq_src);
22951c0b2f7Stbbdev 
23051c0b2f7Stbbdev     REQUIRE_MESSAGE(previous == MoveOperationTracker::special_member_calls(), "Steal move assign operator should not create any new elements");
23151c0b2f7Stbbdev     REQUIRE_MESSAGE(dst == src_copy, "cpq content changed during steal move assignment");
23251c0b2f7Stbbdev     REQUIRE_MESSAGE(!(dst != src_copy), "cpq content changed during steal move assignment");
23351c0b2f7Stbbdev }
23451c0b2f7Stbbdev 
test_steal_move_assign_operator_with_stateful_allocator()23551c0b2f7Stbbdev void test_steal_move_assign_operator_with_stateful_allocator() {
23651c0b2f7Stbbdev     // Use stateful allocator which is propagated on move assignment
23751c0b2f7Stbbdev     using arena_fixture_type = move_support_tests::TwoMemoryArenasFixture<MoveOperationTracker, /*POCMA = */std::true_type>;
23851c0b2f7Stbbdev     using fixture_type = CPQSrcFixture<arena_fixture_type::allocator_type>;
23951c0b2f7Stbbdev 
24051c0b2f7Stbbdev     arena_fixture_type arena_fixture(8 * fixture_type::default_container_size);
24151c0b2f7Stbbdev     fixture_type fixture(arena_fixture.source_allocator);
24251c0b2f7Stbbdev     fixture_type::cpq_type src_copy(fixture.cpq_src);
24351c0b2f7Stbbdev     fixture_type::cpq_type dst(arena_fixture.dst_allocator);
24451c0b2f7Stbbdev 
24551c0b2f7Stbbdev     SpecialMemberCalls previous = MoveOperationTracker::special_member_calls();
24651c0b2f7Stbbdev     dst = std::move(fixture.cpq_src);
24751c0b2f7Stbbdev     REQUIRE_MESSAGE(previous == MoveOperationTracker::special_member_calls(), "Steal move assign operator should not create any new elements");
24851c0b2f7Stbbdev     REQUIRE_MESSAGE(dst == src_copy, "cpq content changed during steal move assignment");
24951c0b2f7Stbbdev     REQUIRE_MESSAGE(!(dst != src_copy), "cpq content changed during steal move assignment");
25051c0b2f7Stbbdev }
25151c0b2f7Stbbdev 
test_per_element_move_assign_operator()25251c0b2f7Stbbdev void test_per_element_move_assign_operator() {
25351c0b2f7Stbbdev     // Use stateful allocator which is not prepagated on move assignment
25451c0b2f7Stbbdev     using arena_fixture_type = move_support_tests::TwoMemoryArenasFixture<MoveOperationTracker, /*POCMA = */std::false_type>;
25551c0b2f7Stbbdev     using fixture_type = CPQSrcFixture<arena_fixture_type::allocator_type>;
25651c0b2f7Stbbdev 
25751c0b2f7Stbbdev     arena_fixture_type arena_fixture(8 * fixture_type::default_container_size);
25851c0b2f7Stbbdev     fixture_type fixture(arena_fixture.source_allocator);
25951c0b2f7Stbbdev     fixture_type::cpq_type src_copy(fixture.cpq_src);
26051c0b2f7Stbbdev     fixture_type::cpq_type dst(arena_fixture.dst_allocator);
26151c0b2f7Stbbdev 
26251c0b2f7Stbbdev     SpecialMemberCalls move_ctor_called_cpq_size_times = MoveOperationTracker::special_member_calls();
26351c0b2f7Stbbdev     move_ctor_called_cpq_size_times.move_ctor_called_times += fixture.container_size;
26451c0b2f7Stbbdev     dst = std::move(fixture.cpq_src);
26551c0b2f7Stbbdev     REQUIRE_MESSAGE(move_ctor_called_cpq_size_times == MoveOperationTracker::special_member_calls(),
26651c0b2f7Stbbdev                     "Per element move assignment should move initialize all new elements");
26751c0b2f7Stbbdev     REQUIRE_MESSAGE(dst == src_copy, "cpq content changed during per element move assignment");
26851c0b2f7Stbbdev     REQUIRE_MESSAGE(!(dst != src_copy), "cpq content changed during per element move assignment");
26951c0b2f7Stbbdev }
27051c0b2f7Stbbdev 
test_cpq_move_constructor()27151c0b2f7Stbbdev void test_cpq_move_constructor() {
27251c0b2f7Stbbdev     test_steal_move_ctor();
27351c0b2f7Stbbdev     test_steal_move_ctor_with_allocator();
27451c0b2f7Stbbdev     test_per_element_move_ctor_with_allocator();
27551c0b2f7Stbbdev }
27651c0b2f7Stbbdev 
test_cpq_move_assignment()27751c0b2f7Stbbdev void test_cpq_move_assignment() {
27851c0b2f7Stbbdev     test_steal_move_assign_operator();
27951c0b2f7Stbbdev     test_steal_move_assign_operator_with_stateful_allocator();
28051c0b2f7Stbbdev     test_per_element_move_assign_operator();
28151c0b2f7Stbbdev }
28251c0b2f7Stbbdev 
28351c0b2f7Stbbdev 
28451c0b2f7Stbbdev struct NoDefaultCtorType {
28551c0b2f7Stbbdev     NoDefaultCtorType() = delete;
28651c0b2f7Stbbdev 
NoDefaultCtorTypeNoDefaultCtorType28751c0b2f7Stbbdev     NoDefaultCtorType( std::size_t val1, std::size_t val2 ) : value1(val1), value2(val2) {}
operator <NoDefaultCtorType28851c0b2f7Stbbdev     bool operator<(const NoDefaultCtorType& other) const {
28951c0b2f7Stbbdev         return value1 + value2 < other.value1 + other.value2;
29051c0b2f7Stbbdev     }
29151c0b2f7Stbbdev 
29251c0b2f7Stbbdev     std::size_t value1, value2;
29351c0b2f7Stbbdev }; // struct NoDefaultCtorType
29451c0b2f7Stbbdev 
29551c0b2f7Stbbdev struct ForwardInEmplaceTester {
29651c0b2f7Stbbdev     int a;
29751c0b2f7Stbbdev     static bool move_ctor_called;
29851c0b2f7Stbbdev     static bool move_assign_called;
29951c0b2f7Stbbdev 
ForwardInEmplaceTesterForwardInEmplaceTester30051c0b2f7Stbbdev     ForwardInEmplaceTester( int val ) : a(val) {}
30151c0b2f7Stbbdev     ForwardInEmplaceTester( const ForwardInEmplaceTester& ) = default;
30251c0b2f7Stbbdev     ForwardInEmplaceTester( ForwardInEmplaceTester&& ) = default;
30351c0b2f7Stbbdev 
ForwardInEmplaceTesterForwardInEmplaceTester30451c0b2f7Stbbdev     ForwardInEmplaceTester( ForwardInEmplaceTester&& obj, int val ) : a(obj.a) {
30551c0b2f7Stbbdev         move_ctor_called = true;
30651c0b2f7Stbbdev         obj.a = val;
30751c0b2f7Stbbdev     }
30851c0b2f7Stbbdev 
30951c0b2f7Stbbdev     ForwardInEmplaceTester& operator=( const ForwardInEmplaceTester& ) = default;
31051c0b2f7Stbbdev 
operator =ForwardInEmplaceTester31151c0b2f7Stbbdev     ForwardInEmplaceTester& operator=( ForwardInEmplaceTester&& obj ) {
31251c0b2f7Stbbdev         a = obj.a;
31351c0b2f7Stbbdev         move_assign_called = true;
31451c0b2f7Stbbdev         return *this;
31551c0b2f7Stbbdev     }
31651c0b2f7Stbbdev 
operator <ForwardInEmplaceTester31751c0b2f7Stbbdev     bool operator<( const ForwardInEmplaceTester& ) const { return true; }
31851c0b2f7Stbbdev }; // struct ForwardInEmplaceTester
31951c0b2f7Stbbdev 
32051c0b2f7Stbbdev bool ForwardInEmplaceTester::move_ctor_called = false;
32151c0b2f7Stbbdev bool ForwardInEmplaceTester::move_assign_called = false;
32251c0b2f7Stbbdev 
test_move_support_in_push_pop()32351c0b2f7Stbbdev void test_move_support_in_push_pop() {
32451c0b2f7Stbbdev     std::size_t& mcct = MoveOperationTracker::move_ctor_called_times;
32551c0b2f7Stbbdev     std::size_t& ccct = MoveOperationTracker::copy_ctor_called_times;
32651c0b2f7Stbbdev     std::size_t& cact = MoveOperationTracker::copy_assign_called_times;
32751c0b2f7Stbbdev     std::size_t& mact = MoveOperationTracker::move_assign_called_times;
32851c0b2f7Stbbdev     mcct = ccct = cact = mact = 0;
32951c0b2f7Stbbdev 
33049e08aacStbbdev     oneapi::tbb::concurrent_priority_queue<MoveOperationTracker> q1;
33151c0b2f7Stbbdev 
33251c0b2f7Stbbdev     REQUIRE_MESSAGE(mcct == 0, "Value must be zero-initialized");
33351c0b2f7Stbbdev     REQUIRE_MESSAGE(ccct == 0, "Value must be zero-initialized");
33451c0b2f7Stbbdev 
33551c0b2f7Stbbdev     q1.push(MoveOperationTracker{});
33651c0b2f7Stbbdev     REQUIRE_MESSAGE(mcct > 0, "Not working push(T&&)");
33751c0b2f7Stbbdev     REQUIRE_MESSAGE(ccct == 0, "Copying of arg occurred during push(T&&)");
33851c0b2f7Stbbdev 
33951c0b2f7Stbbdev     MoveOperationTracker ob;
34051c0b2f7Stbbdev     const std::size_t prev_mcct = mcct;
34151c0b2f7Stbbdev     q1.push(std::move(ob));
34251c0b2f7Stbbdev     REQUIRE_MESSAGE(mcct > prev_mcct, "Not working push(T&&)");
34351c0b2f7Stbbdev     REQUIRE_MESSAGE(ccct == 0, "Copying of arg occurred during push(T&&)");
34451c0b2f7Stbbdev 
34551c0b2f7Stbbdev     REQUIRE_MESSAGE(cact == 0, "Copy assignment called during push(T&&)");
34651c0b2f7Stbbdev     const std::size_t prev_mact = mact;
34751c0b2f7Stbbdev     q1.try_pop(ob);
34851c0b2f7Stbbdev     REQUIRE_MESSAGE(cact == 0, "Copy assignment called during try_pop(T&)");
34951c0b2f7Stbbdev     REQUIRE_MESSAGE(mact > prev_mact, "Move assignment was not called during try_pop(T&)");
35051c0b2f7Stbbdev 
35149e08aacStbbdev     oneapi::tbb::concurrent_priority_queue<NoDefaultCtorType> q2;
35251c0b2f7Stbbdev     q2.emplace(15, 3);
35351c0b2f7Stbbdev     q2.emplace(2, 35);
35451c0b2f7Stbbdev     q2.emplace(8, 8);
35551c0b2f7Stbbdev 
35651c0b2f7Stbbdev     NoDefaultCtorType o(0, 0);
35751c0b2f7Stbbdev     q2.try_pop(o);
35851c0b2f7Stbbdev     REQUIRE_MESSAGE((o.value1 == 2 && o.value2 == 35), "Unexpected data popped; possible emplace() failure");
35951c0b2f7Stbbdev     q2.try_pop(o);
36051c0b2f7Stbbdev     REQUIRE_MESSAGE((o.value1 == 15 && o.value2 == 3), "Unexpected data popped; possible emplace() failure");
36151c0b2f7Stbbdev     q2.try_pop(o);
36251c0b2f7Stbbdev     REQUIRE_MESSAGE((o.value1 == 8 && o.value2 == 8), "Unexpected data popped; possible emplace() failure");
36351c0b2f7Stbbdev     REQUIRE_MESSAGE(!q2.try_pop(o), "The queue should be empty");
36451c0b2f7Stbbdev 
36549e08aacStbbdev     oneapi::tbb::concurrent_priority_queue<ForwardInEmplaceTester> q3;
36651c0b2f7Stbbdev     REQUIRE(ForwardInEmplaceTester::move_ctor_called == false);
36751c0b2f7Stbbdev     q3.emplace(ForwardInEmplaceTester{5}, 2);
36851c0b2f7Stbbdev     REQUIRE_MESSAGE(ForwardInEmplaceTester::move_ctor_called == true, "Not used std::forward in emplace()");
36951c0b2f7Stbbdev     ForwardInEmplaceTester obj(0);
37051c0b2f7Stbbdev     q3.try_pop(obj);
37151c0b2f7Stbbdev 
37251c0b2f7Stbbdev     REQUIRE_MESSAGE(ForwardInEmplaceTester::move_assign_called == true, "Not used move assignment in try_pop");
37351c0b2f7Stbbdev     REQUIRE_MESSAGE(obj.a == 5, "Not used std::forward in emplace");
37451c0b2f7Stbbdev     REQUIRE_MESSAGE(!q3.try_pop(obj), "The queue should be empty");
37551c0b2f7Stbbdev }
37651c0b2f7Stbbdev 
37751c0b2f7Stbbdev // Comparator with assert in default ctor
37851c0b2f7Stbbdev template <typename T>
37951c0b2f7Stbbdev class LessA : public std::less<T> {
38051c0b2f7Stbbdev public:
LessA(bool no_assert=false)38151c0b2f7Stbbdev     explicit LessA( bool no_assert = false ) {
38251c0b2f7Stbbdev         REQUIRE_MESSAGE(no_assert, "Default ctor should not be called");
38351c0b2f7Stbbdev     }
38451c0b2f7Stbbdev }; // class LessA
38551c0b2f7Stbbdev 
38651c0b2f7Stbbdev // TODO: consider use of TEST_SUITE for these tests
38751c0b2f7Stbbdev // TODO: combine with the constructors test from the common part
test_ctors_dtor_accessors()38851c0b2f7Stbbdev void test_ctors_dtor_accessors() {
38951c0b2f7Stbbdev     std::vector<int> v;
39051c0b2f7Stbbdev     std::allocator<int> a;
39151c0b2f7Stbbdev 
39249e08aacStbbdev     using cpq_type = oneapi::tbb::concurrent_priority_queue<int, std::less<int>>;
39349e08aacStbbdev     using cpq_with_compare_type = oneapi::tbb::concurrent_priority_queue<int, LessA<int>>;
39449e08aacStbbdev     using cpq_with_compare_and_allocator_type = oneapi::tbb::concurrent_priority_queue<int, LessA<int>, std::allocator<int>>;
39551c0b2f7Stbbdev 
39651c0b2f7Stbbdev     LessA<int> l(true);
39751c0b2f7Stbbdev 
39851c0b2f7Stbbdev     // Test default ctor
39951c0b2f7Stbbdev     cpq_type cpq1;
40051c0b2f7Stbbdev     REQUIRE_MESSAGE(cpq1.size() == 0, "Failed size test for default ctor");
40151c0b2f7Stbbdev     REQUIRE_MESSAGE(cpq1.empty(), "Failed empty test for default ctor");
40251c0b2f7Stbbdev 
40351c0b2f7Stbbdev     // Test capacity ctor
40451c0b2f7Stbbdev     cpq_type cpq2(42);
40551c0b2f7Stbbdev     REQUIRE_MESSAGE(cpq2.size() == 0, "Failed size test for capacity ctor");
40651c0b2f7Stbbdev     REQUIRE_MESSAGE(cpq2.empty(), "Failed empty test for capacity ctor");
40751c0b2f7Stbbdev 
40851c0b2f7Stbbdev     // Test compare ctor
40951c0b2f7Stbbdev     cpq_with_compare_type cpq3(l);
41051c0b2f7Stbbdev     REQUIRE_MESSAGE(cpq3.size() == 0, "Failed size test for compare ctor");
41151c0b2f7Stbbdev     REQUIRE_MESSAGE(cpq3.empty(), "Failed empty test for compare ctor");
41251c0b2f7Stbbdev 
41351c0b2f7Stbbdev     // Test compare+allocator ctor
41451c0b2f7Stbbdev     cpq_with_compare_and_allocator_type cpq4(l, a);
41551c0b2f7Stbbdev     REQUIRE_MESSAGE(cpq4.size() == 0, "Failed size test for compare+allocator ctor");
41651c0b2f7Stbbdev     REQUIRE_MESSAGE(cpq4.empty(), "Failed empty test for compare+allocator ctor");
41751c0b2f7Stbbdev 
41851c0b2f7Stbbdev     // Test capacity+compare ctor
41951c0b2f7Stbbdev     cpq_with_compare_type cpq5(42, l);
42051c0b2f7Stbbdev     REQUIRE_MESSAGE(cpq5.size() == 0, "Failed size test for capacity+compare ctor");
42151c0b2f7Stbbdev     REQUIRE_MESSAGE(cpq5.empty(), "Failed empty test for capacity+compare ctor");
42251c0b2f7Stbbdev 
42351c0b2f7Stbbdev     // Test capacity+compare+allocator ctor
42451c0b2f7Stbbdev     cpq_with_compare_and_allocator_type cpq6(42, l, a);
42551c0b2f7Stbbdev     REQUIRE_MESSAGE(cpq6.size() == 0, "Failed size test for capacity+compare+allocator ctor");
42651c0b2f7Stbbdev     REQUIRE_MESSAGE(cpq6.empty(), "Failed empty test for capacity+compare+allocator ctor");
42751c0b2f7Stbbdev 
42851c0b2f7Stbbdev     // Test half-open range ctor
42951c0b2f7Stbbdev     for (int i = 0; i < 42; ++i) {
43051c0b2f7Stbbdev         v.emplace_back(i);
43151c0b2f7Stbbdev     }
43251c0b2f7Stbbdev     using equality_comparison_helpers::toVector;
43351c0b2f7Stbbdev     cpq_type cpq7(v.begin(), v.end());
43451c0b2f7Stbbdev     REQUIRE_MESSAGE(cpq7.size() == 42, "Failed size test for half-open range ctor");
43551c0b2f7Stbbdev     REQUIRE_MESSAGE(!cpq7.empty(), "Failed empty test for half-open range test");
43651c0b2f7Stbbdev     REQUIRE_MESSAGE(v == toVector(cpq7), "Failed equality test for half-open range ctor");
43751c0b2f7Stbbdev 
43851c0b2f7Stbbdev     // Test half-open range + compare ctor
43951c0b2f7Stbbdev     cpq_with_compare_type cpq8(v.begin(), v.end(), l);
44051c0b2f7Stbbdev     REQUIRE_MESSAGE(cpq8.size() == 42, "Failed size test for half-open range+compare ctor");
44151c0b2f7Stbbdev     REQUIRE_MESSAGE(!cpq8.empty(), "Failed empty test for half-open range+compare ctor");
44251c0b2f7Stbbdev     REQUIRE_MESSAGE(v == toVector(cpq8), "Failed equality test for half-open range+compare ctor");
44351c0b2f7Stbbdev 
44451c0b2f7Stbbdev     // Test copy ctor
44551c0b2f7Stbbdev     cpq_type cpq9(cpq7);
44651c0b2f7Stbbdev     REQUIRE_MESSAGE(cpq9.size() == cpq7.size(), "Failed size test for copy ctor");
44751c0b2f7Stbbdev     REQUIRE_MESSAGE(!cpq9.empty(), "Failed empty test for copy ctor");
44851c0b2f7Stbbdev     REQUIRE_MESSAGE(cpq9 == cpq7, "Failed equality test for copy ctor");
44951c0b2f7Stbbdev }
45051c0b2f7Stbbdev 
test_assignment_clear_swap()45151c0b2f7Stbbdev void test_assignment_clear_swap() {
45251c0b2f7Stbbdev     using equality_comparison_helpers::toVector;
45349e08aacStbbdev     using cpq_type = oneapi::tbb::concurrent_priority_queue<int, std::less<int>>;
45451c0b2f7Stbbdev     std::vector<int> v;
45551c0b2f7Stbbdev     int e;
45651c0b2f7Stbbdev 
45751c0b2f7Stbbdev     for( int i = 0; i < 42; ++i )
45851c0b2f7Stbbdev         v.emplace_back(i);
45951c0b2f7Stbbdev 
46051c0b2f7Stbbdev     cpq_type q(v.begin(), v.end());
46151c0b2f7Stbbdev     cpq_type qo;
46251c0b2f7Stbbdev 
46351c0b2f7Stbbdev     // Test assignment
46451c0b2f7Stbbdev     qo = q;
46551c0b2f7Stbbdev     REQUIRE_MESSAGE(qo.size() == 42, "Failed assignment size test");
46651c0b2f7Stbbdev     REQUIRE_MESSAGE(!qo.empty(), "Failed assignment empty test");
46751c0b2f7Stbbdev     REQUIRE_MESSAGE(v == toVector(qo), "Failed assignment equality test");
46851c0b2f7Stbbdev     REQUIRE_MESSAGE(qo == q, "Failed assignment equality test");
46951c0b2f7Stbbdev     REQUIRE_MESSAGE(!(qo != q), "Failed assignment inequality test");
47051c0b2f7Stbbdev 
47151c0b2f7Stbbdev     cpq_type assigned_q;
47251c0b2f7Stbbdev     // Testing assign member function
47351c0b2f7Stbbdev     assigned_q.assign(v.begin(), v.end());
47451c0b2f7Stbbdev     REQUIRE_MESSAGE(assigned_q.size() == 42, "Failed assign size test");
47551c0b2f7Stbbdev     REQUIRE_MESSAGE(!assigned_q.empty(), "Failed assign empty test");
47651c0b2f7Stbbdev     REQUIRE_MESSAGE(v == toVector(assigned_q), "Failed assign equality test");
47751c0b2f7Stbbdev 
47851c0b2f7Stbbdev     // Testing clear()
47951c0b2f7Stbbdev     q.clear();
48051c0b2f7Stbbdev     REQUIRE_MESSAGE(q.size() == 0, "Failed clear size test");
48151c0b2f7Stbbdev     REQUIRE_MESSAGE(q.empty(), "Failed clear empty test");
48251c0b2f7Stbbdev 
48351c0b2f7Stbbdev     // Test assignment again
48451c0b2f7Stbbdev     for (std::size_t i = 0; i < 5; ++i)
48551c0b2f7Stbbdev         qo.try_pop(e);
48651c0b2f7Stbbdev 
48751c0b2f7Stbbdev     q = qo;
48851c0b2f7Stbbdev     REQUIRE_MESSAGE(q.size() == 37, "Failed assignment size test");
48951c0b2f7Stbbdev     REQUIRE_MESSAGE(!q.empty(), "Failed assignment empty test");
49051c0b2f7Stbbdev 
49151c0b2f7Stbbdev     for (std::size_t i = 0; i < 5; ++i)
49251c0b2f7Stbbdev         qo.try_pop(e);
49351c0b2f7Stbbdev 
49451c0b2f7Stbbdev     q.swap(qo);
49551c0b2f7Stbbdev 
49651c0b2f7Stbbdev     REQUIRE_MESSAGE(q.size() == 32, "Failed swap size test");
49751c0b2f7Stbbdev     REQUIRE_MESSAGE(!q.empty(), "Failed swap empty test");
49851c0b2f7Stbbdev     REQUIRE_MESSAGE(qo.size() == 37, "Failed swap size test");
49951c0b2f7Stbbdev     REQUIRE_MESSAGE(!qo.empty(), "Failed swap empty test");
50051c0b2f7Stbbdev }
50151c0b2f7Stbbdev 
test_serial_push_pop()50251c0b2f7Stbbdev void test_serial_push_pop() {
50349e08aacStbbdev     oneapi::tbb::concurrent_priority_queue<int, std::less<int>> q(MAX_ITER);
50451c0b2f7Stbbdev     int e = 42;
50551c0b2f7Stbbdev     int prev = INT_MAX;
50651c0b2f7Stbbdev     std::size_t count = 0;
50751c0b2f7Stbbdev 
50851c0b2f7Stbbdev     // Test serial push
50951c0b2f7Stbbdev     for (std::size_t i = 0; i < MAX_ITER; ++i) {
51051c0b2f7Stbbdev         push_selector(q, e, i);
51151c0b2f7Stbbdev         e = e*-1 + int(i);
51251c0b2f7Stbbdev     }
51351c0b2f7Stbbdev 
51451c0b2f7Stbbdev     REQUIRE_MESSAGE(q.size() == MAX_ITER, "Failed push size test");
51551c0b2f7Stbbdev     REQUIRE_MESSAGE(!q.empty(), "Failed push empty test");
51651c0b2f7Stbbdev 
51751c0b2f7Stbbdev     // Test serial pop
51851c0b2f7Stbbdev     while(!q.empty()) {
51951c0b2f7Stbbdev         REQUIRE_MESSAGE(q.try_pop(e), "Failed pop test");
52051c0b2f7Stbbdev         REQUIRE_MESSAGE(prev >= e, "Failed pop priority test");
52151c0b2f7Stbbdev         prev = e;
52251c0b2f7Stbbdev         ++count;
52351c0b2f7Stbbdev 
52451c0b2f7Stbbdev         REQUIRE_MESSAGE(q.size() == MAX_ITER - count, "Failed pop size test");
52551c0b2f7Stbbdev         REQUIRE_MESSAGE((!q.empty() || count == MAX_ITER), "Failed pop empty test");
52651c0b2f7Stbbdev     }
52751c0b2f7Stbbdev     REQUIRE_MESSAGE(!q.try_pop(e), "Failed: successful pop from the empty queue");
52851c0b2f7Stbbdev }
52951c0b2f7Stbbdev 
test_concurrent(std::size_t n)53051c0b2f7Stbbdev void test_concurrent(std::size_t n) {
53151c0b2f7Stbbdev     test_parallel_push_pop<std::less<int>>(n, INT_MAX, INT_MIN);
53251c0b2f7Stbbdev     test_parallel_push_pop<std::less<int>>(n, (unsigned char)CHAR_MAX, (unsigned char)CHAR_MIN);
53351c0b2f7Stbbdev 
53451c0b2f7Stbbdev     test_flogger<std::less<int>, int>(n);
53551c0b2f7Stbbdev     test_flogger<std::less<int>, unsigned char>(n);
53651c0b2f7Stbbdev 
537b15aabb3Stbbdev     MoveOperationTrackerConc::copy_assign_called_times = 0;
538b15aabb3Stbbdev     test_flogger<std::less<MoveOperationTrackerConc>, MoveOperationTrackerConc>(n);
539b15aabb3Stbbdev     REQUIRE_MESSAGE(MoveOperationTrackerConc::copy_assign_called_times == 0, "Copy assignment called during try_pop");
54051c0b2f7Stbbdev }
54151c0b2f7Stbbdev 
test_multithreading()54251c0b2f7Stbbdev void test_multithreading() {
54351c0b2f7Stbbdev     for (std::size_t n = utils::MinThread; n != utils::MaxThread; ++n) {
54451c0b2f7Stbbdev         test_concurrent(n);
54551c0b2f7Stbbdev     }
54651c0b2f7Stbbdev }
54751c0b2f7Stbbdev 
54851c0b2f7Stbbdev struct CPQTraits {
54951c0b2f7Stbbdev     template <typename T>
55051c0b2f7Stbbdev     using container_value_type = T;
55151c0b2f7Stbbdev 
55251c0b2f7Stbbdev     template <typename T, typename Allocator>
55349e08aacStbbdev     using container_type = oneapi::tbb::concurrent_priority_queue<T, std::less<T>, Allocator>;
55451c0b2f7Stbbdev }; // struct CPQTraits
55551c0b2f7Stbbdev 
55651c0b2f7Stbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
55751c0b2f7Stbbdev template <template <typename...>typename TQueue>
TestDeductionGuides()55851c0b2f7Stbbdev void TestDeductionGuides() {
55951c0b2f7Stbbdev     using ComplexType = const std::string*;
56051c0b2f7Stbbdev     std::string s("s");
56151c0b2f7Stbbdev     std::vector<ComplexType> v;
56251c0b2f7Stbbdev     auto l = {ComplexType(&s), ComplexType(&s) };
56351c0b2f7Stbbdev 
56451c0b2f7Stbbdev     // check TQueue(InputIterator, InputIterator)
56551c0b2f7Stbbdev     TQueue qv(v.begin(), v.end());
56651c0b2f7Stbbdev     static_assert(std::is_same<decltype(qv), TQueue<ComplexType> >::value);
56751c0b2f7Stbbdev 
56851c0b2f7Stbbdev     // check TQueue(InputIterator, InputIterator, Allocator)
56951c0b2f7Stbbdev     TQueue qva(v.begin(), v.end(), std::allocator<ComplexType>());
57051c0b2f7Stbbdev     static_assert(std::is_same<decltype(qva), TQueue<ComplexType, std::less<ComplexType>,
57151c0b2f7Stbbdev         std::allocator<ComplexType>>>::value);
57251c0b2f7Stbbdev 
57351c0b2f7Stbbdev     // check TQueue(InputIterator, InputIterator, Compare)
57451c0b2f7Stbbdev     TQueue qvc(v.begin(), v.end(), LessA<ComplexType>(true));
57551c0b2f7Stbbdev     static_assert(std::is_same<decltype(qvc), TQueue<ComplexType, LessA<ComplexType>>>::value);
57651c0b2f7Stbbdev 
57751c0b2f7Stbbdev     // check TQueue(InputIterator, InputIterator, Compare, Allocator)
57851c0b2f7Stbbdev     TQueue qvca(v.begin(), v.end(), LessA<ComplexType>(true), std::allocator<ComplexType>());
57951c0b2f7Stbbdev     static_assert(std::is_same<decltype(qvca), TQueue<ComplexType, LessA<ComplexType>,
58051c0b2f7Stbbdev         std::allocator<ComplexType>>>::value);
58151c0b2f7Stbbdev 
58251c0b2f7Stbbdev     // check TQueue(std::initializer_list)
58351c0b2f7Stbbdev     TQueue ql(l);
58451c0b2f7Stbbdev     static_assert(std::is_same<decltype(ql), TQueue<ComplexType>>::value);
58551c0b2f7Stbbdev 
58651c0b2f7Stbbdev     // check TQueue(std::initializer_list, Allocator)
58751c0b2f7Stbbdev     TQueue qla(l, std::allocator<ComplexType>());
58851c0b2f7Stbbdev     static_assert(std::is_same<decltype(qla), TQueue<ComplexType, std::less<ComplexType>,
58951c0b2f7Stbbdev         std::allocator<ComplexType>>>::value);
59051c0b2f7Stbbdev 
59151c0b2f7Stbbdev     // check TQueue(std::initializer_list, Compare)
59251c0b2f7Stbbdev     TQueue qlc(l, LessA<ComplexType>(true));
59351c0b2f7Stbbdev     static_assert(std::is_same<decltype(qlc), TQueue<ComplexType, LessA<ComplexType>>>::value);
59451c0b2f7Stbbdev 
59551c0b2f7Stbbdev     // check TQueue(std::initializer_list, Compare, Allocator)
59651c0b2f7Stbbdev     TQueue qlca(l, LessA<ComplexType>(true), std::allocator<ComplexType>());
59751c0b2f7Stbbdev     static_assert(std::is_same<decltype(qlca), TQueue<ComplexType, LessA<ComplexType>,
59851c0b2f7Stbbdev         std::allocator<ComplexType>>>::value);
59951c0b2f7Stbbdev 
60051c0b2f7Stbbdev     // check TQueue(TQueue &)
60151c0b2f7Stbbdev     TQueue qc(qv);
60251c0b2f7Stbbdev     static_assert(std::is_same<decltype(qv), decltype(qv)>::value);
60351c0b2f7Stbbdev 
60451c0b2f7Stbbdev     // check TQueue(TQueue &, Allocator)
60551c0b2f7Stbbdev     TQueue qca(qva, std::allocator<ComplexType>());
60651c0b2f7Stbbdev     static_assert(std::is_same<decltype(qca), decltype(qva)>::value);
60751c0b2f7Stbbdev 
60851c0b2f7Stbbdev     // check TQueue(TQueue &&)
60951c0b2f7Stbbdev     TQueue qm(std::move(qv));
61051c0b2f7Stbbdev     static_assert(std::is_same<decltype(qm), decltype(qv)>::value);
61151c0b2f7Stbbdev 
61251c0b2f7Stbbdev     // check TQueue(TQueue &&, Allocator)
61351c0b2f7Stbbdev     TQueue qma(std::move(qva), std::allocator<ComplexType>());
61451c0b2f7Stbbdev     static_assert(std::is_same<decltype(qma), decltype(qva)>::value);
61551c0b2f7Stbbdev }
61651c0b2f7Stbbdev #endif // __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
61751c0b2f7Stbbdev 
618b15aabb3Stbbdev template <typename CPQType>
TestComparisonsBasic()619b15aabb3Stbbdev void TestComparisonsBasic() {
620b15aabb3Stbbdev     using comparisons_testing::testEqualityComparisons;
621b15aabb3Stbbdev     CPQType c1, c2;
622b15aabb3Stbbdev     testEqualityComparisons</*ExpectEqual = */true>(c1, c2);
623b15aabb3Stbbdev 
624b15aabb3Stbbdev     c1.emplace(1);
625b15aabb3Stbbdev     testEqualityComparisons</*ExpectEqual = */false>(c1, c2);
626b15aabb3Stbbdev 
627b15aabb3Stbbdev     c2.emplace(1);
628b15aabb3Stbbdev     testEqualityComparisons</*ExpectEqual = */true>(c1, c2);
629b15aabb3Stbbdev }
630b15aabb3Stbbdev 
631b15aabb3Stbbdev template <typename TwoWayComparableCPQType>
TestTwoWayComparableCPQ()632b15aabb3Stbbdev void TestTwoWayComparableCPQ() {
633b15aabb3Stbbdev     TwoWayComparableCPQType c1, c2;
634b15aabb3Stbbdev     c1.emplace(1);
635b15aabb3Stbbdev     c2.emplace(1);
636b15aabb3Stbbdev     comparisons_testing::TwoWayComparable::reset();
637b15aabb3Stbbdev     REQUIRE_MESSAGE(c1 == c2, "Incorrect operator == result");
638b15aabb3Stbbdev     comparisons_testing::check_equality_comparison();
639b15aabb3Stbbdev     REQUIRE_MESSAGE(!(c1 != c2), "Incorrect operator != result");
640b15aabb3Stbbdev     comparisons_testing::check_equality_comparison();
641b15aabb3Stbbdev }
642b15aabb3Stbbdev 
TestCPQComparisons()643b15aabb3Stbbdev void TestCPQComparisons() {
644b15aabb3Stbbdev     using integral_container = oneapi::tbb::concurrent_priority_queue<int>;
645b15aabb3Stbbdev     using two_way_comparable_container = oneapi::tbb::concurrent_priority_queue<comparisons_testing::TwoWayComparable>;
646b15aabb3Stbbdev 
647b15aabb3Stbbdev     TestComparisonsBasic<integral_container>();
648b15aabb3Stbbdev     TestComparisonsBasic<two_way_comparable_container>();
649b15aabb3Stbbdev     TestTwoWayComparableCPQ<two_way_comparable_container>();
650b15aabb3Stbbdev }
651b15aabb3Stbbdev 
65251c0b2f7Stbbdev // Testing basic operations with concurrent_priority_queue with integral value type
65351c0b2f7Stbbdev //! \brief \ref interface \ref requirement
65451c0b2f7Stbbdev TEST_CASE("basic test for concurrent_priority_queue") {
65551c0b2f7Stbbdev     test_to_vector(); // Test concurrent_priority_queue helper
65651c0b2f7Stbbdev     test_basic();
65751c0b2f7Stbbdev }
65851c0b2f7Stbbdev 
65951c0b2f7Stbbdev // Testing std::initializer_list interfaces in concurrent_priority_queue
66051c0b2f7Stbbdev //! \brief \ref interface \ref requirement
66151c0b2f7Stbbdev TEST_CASE("std::initializer_list support in concurrent_priority_queue") {
66251c0b2f7Stbbdev     test_initializer_list();
66351c0b2f7Stbbdev }
66451c0b2f7Stbbdev 
66551c0b2f7Stbbdev //! Testing concurrent_priority_queue moving constructors
66651c0b2f7Stbbdev //! \brief \ref interface \ref requirement
66751c0b2f7Stbbdev TEST_CASE("concurrent_priority_queue move constructor") {
66851c0b2f7Stbbdev     test_cpq_move_constructor();
66951c0b2f7Stbbdev }
67051c0b2f7Stbbdev 
67151c0b2f7Stbbdev //! Testing concurrent_priority_queue move assignment operator with different allocator types
67251c0b2f7Stbbdev //! \brief \ref interface \ref requirement
67351c0b2f7Stbbdev TEST_CASE("concurrent_priority_queue move assignment operator") {
67451c0b2f7Stbbdev     test_cpq_move_assignment();
67551c0b2f7Stbbdev }
67651c0b2f7Stbbdev 
67751c0b2f7Stbbdev //! Testing move semantics on basic push-pop operations
67851c0b2f7Stbbdev //! \brief \ref requirement
67951c0b2f7Stbbdev TEST_CASE("move semantics support on push-pop operations") {
68051c0b2f7Stbbdev     test_move_support_in_push_pop();
68151c0b2f7Stbbdev }
68251c0b2f7Stbbdev 
68351c0b2f7Stbbdev //! \brief \ref interface \ref requirement
68451c0b2f7Stbbdev TEST_CASE("constructors, destructor and accessors") {
68551c0b2f7Stbbdev     test_ctors_dtor_accessors();
68651c0b2f7Stbbdev }
68751c0b2f7Stbbdev 
68851c0b2f7Stbbdev //! \brief \ref interface \ref requirement
68951c0b2f7Stbbdev TEST_CASE("assignment, clear and swap operations") {
69051c0b2f7Stbbdev     test_assignment_clear_swap();
69151c0b2f7Stbbdev }
69251c0b2f7Stbbdev 
69351c0b2f7Stbbdev //! Testing push-pop operations in concurrent_priority_queue
69451c0b2f7Stbbdev //! \brief \ref requirement
69551c0b2f7Stbbdev TEST_CASE("serial push-pop") {
69651c0b2f7Stbbdev     test_serial_push_pop();
69751c0b2f7Stbbdev }
69851c0b2f7Stbbdev 
69951c0b2f7Stbbdev //! Testing push-pop operations in concurrent_priority_queue with multithreading
70051c0b2f7Stbbdev //! \brief \ref requirement
70151c0b2f7Stbbdev TEST_CASE("multithreading support in concurrent_priority_queue") {
70251c0b2f7Stbbdev     test_multithreading();
70351c0b2f7Stbbdev }
70451c0b2f7Stbbdev 
705*478de5b1Stbbdev #if !_MSC_VER || _MSC_VER > 1900
706*478de5b1Stbbdev // MSVC 2015 does not provide required level of allocator support for standard containers
707*478de5b1Stbbdev 
70851c0b2f7Stbbdev //! \brief \ref requirement
70951c0b2f7Stbbdev TEST_CASE("std::allocator_traits support in concurrent_priority_queue") {
71051c0b2f7Stbbdev     test_allocator_traits_support<CPQTraits>();
71151c0b2f7Stbbdev }
712*478de5b1Stbbdev #endif
71351c0b2f7Stbbdev 
71451c0b2f7Stbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
71551c0b2f7Stbbdev //! Testing Class Template Argument Deduction in concurrent_priority_queue
71651c0b2f7Stbbdev //! \brief \ref interface \ref requirement
71751c0b2f7Stbbdev TEST_CASE("CTAD support in concurrent_priority_queue") {
71849e08aacStbbdev     TestDeductionGuides<oneapi::tbb::concurrent_priority_queue>();
71951c0b2f7Stbbdev }
72051c0b2f7Stbbdev #endif // __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
721b15aabb3Stbbdev 
722b15aabb3Stbbdev //! \brief \ref interface \ref requirement
723b15aabb3Stbbdev TEST_CASE("concurrent_priority_queue iterator comparisons") {
724b15aabb3Stbbdev     TestCPQComparisons();
725b15aabb3Stbbdev }
726