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
17*b15aabb3Stbbdev #if __INTEL_COMPILER && _MSC_VER
18*b15aabb3Stbbdev #pragma warning(disable : 2586) // decorated name length exceeded, name was truncated
19*b15aabb3Stbbdev #endif
20*b15aabb3Stbbdev
2151c0b2f7Stbbdev #include <common/concurrent_priority_queue_common.h>
2251c0b2f7Stbbdev #include <common/containers_common.h>
2351c0b2f7Stbbdev
2451c0b2f7Stbbdev //! \file test_concurrent_priority_queue.cpp
2551c0b2f7Stbbdev //! \brief Test for [containers.concurrent_priority_queue] specification
2651c0b2f7Stbbdev
test_cpq_with_smart_pointers()2751c0b2f7Stbbdev void test_cpq_with_smart_pointers() {
2851c0b2f7Stbbdev const int NUMBER = 10;
2951c0b2f7Stbbdev
3051c0b2f7Stbbdev utils::FastRandom<> rnd(1234);
3151c0b2f7Stbbdev
3251c0b2f7Stbbdev std::vector<std::shared_ptr<int>> shared_pointers;
3351c0b2f7Stbbdev for (int i = 0; i < NUMBER; ++i ) {
3451c0b2f7Stbbdev const int rnd_get = rnd.get();
3551c0b2f7Stbbdev shared_pointers.emplace_back(std::make_shared<int>(rnd_get));
3651c0b2f7Stbbdev }
3751c0b2f7Stbbdev std::vector<std::weak_ptr<int>> weak_pointers;
3851c0b2f7Stbbdev std::copy(shared_pointers.begin(), shared_pointers.end(), std::back_inserter(weak_pointers));
3951c0b2f7Stbbdev
4051c0b2f7Stbbdev type_tester(shared_pointers, LessForSmartPointers{});
4151c0b2f7Stbbdev type_tester(weak_pointers, LessForSmartPointers{});
4251c0b2f7Stbbdev
4351c0b2f7Stbbdev std::vector<int> arrInt;
4451c0b2f7Stbbdev for (int i = 0; i < NUMBER; ++i)
4551c0b2f7Stbbdev arrInt.emplace_back(rnd.get());
4651c0b2f7Stbbdev
4751c0b2f7Stbbdev type_tester_unique_ptr(arrInt); // Test std::unique_ptr
4851c0b2f7Stbbdev }
4951c0b2f7Stbbdev
5051c0b2f7Stbbdev struct MyDataType {
5151c0b2f7Stbbdev std::size_t priority;
5251c0b2f7Stbbdev char padding[tbb::detail::max_nfs_size - sizeof(int) % tbb::detail::max_nfs_size];
5351c0b2f7Stbbdev
5451c0b2f7Stbbdev MyDataType() = default;
MyDataTypeMyDataType5551c0b2f7Stbbdev MyDataType( int val ) : priority(std::size_t(val)) {}
5651c0b2f7Stbbdev
operator +MyDataType5751c0b2f7Stbbdev const MyDataType operator+( const MyDataType& other ) const {
5851c0b2f7Stbbdev return MyDataType(int(priority + other.priority));
5951c0b2f7Stbbdev }
6051c0b2f7Stbbdev
operator ==MyDataType6151c0b2f7Stbbdev bool operator==(const MyDataType& other) const {
6251c0b2f7Stbbdev return this->priority == other.priority;
6351c0b2f7Stbbdev }
6451c0b2f7Stbbdev }; // struct MyDataType
6551c0b2f7Stbbdev
6651c0b2f7Stbbdev const MyDataType DATA_MIN(INT_MIN);
6751c0b2f7Stbbdev const MyDataType DATA_MAX(INT_MAX);
6851c0b2f7Stbbdev
6951c0b2f7Stbbdev struct MyLess {
operator ()MyLess7051c0b2f7Stbbdev bool operator()( const MyDataType d1, const MyDataType d2 ) const {
7151c0b2f7Stbbdev return d1.priority < d2.priority;
7251c0b2f7Stbbdev }
7351c0b2f7Stbbdev }; // struct MyLess
7451c0b2f7Stbbdev
test_concurrent(std::size_t n)7551c0b2f7Stbbdev void test_concurrent( std::size_t n ) {
7651c0b2f7Stbbdev test_parallel_push_pop<MyLess>(n, DATA_MAX, DATA_MIN);
7751c0b2f7Stbbdev test_flogger<MyLess, MyDataType>(n);
7851c0b2f7Stbbdev }
7951c0b2f7Stbbdev
test_multithreading()8051c0b2f7Stbbdev void test_multithreading() {
8151c0b2f7Stbbdev for (std::size_t n = utils::MinThread; n != utils::MaxThread; ++n) {
8251c0b2f7Stbbdev test_concurrent(n);
8351c0b2f7Stbbdev }
8451c0b2f7Stbbdev }
8551c0b2f7Stbbdev
8651c0b2f7Stbbdev struct MyThrowingType : public MyDataType {
8751c0b2f7Stbbdev static int throw_flag;
8851c0b2f7Stbbdev MyThrowingType() = default;
MyThrowingTypeMyThrowingType8951c0b2f7Stbbdev MyThrowingType( const MyThrowingType& src ) : MyDataType(src) {
9051c0b2f7Stbbdev if (throw_flag) {
9151c0b2f7Stbbdev TBB_TEST_THROW(42);
9251c0b2f7Stbbdev }
9351c0b2f7Stbbdev }
9451c0b2f7Stbbdev
operator =MyThrowingType9551c0b2f7Stbbdev MyThrowingType& operator=( const MyThrowingType& other ) {
9651c0b2f7Stbbdev priority = other.priority;
9751c0b2f7Stbbdev return *this;
9851c0b2f7Stbbdev }
9951c0b2f7Stbbdev };
10051c0b2f7Stbbdev
10151c0b2f7Stbbdev int MyThrowingType::throw_flag = 0;
10251c0b2f7Stbbdev
10351c0b2f7Stbbdev using CPQExTestType = tbb::concurrent_priority_queue<MyThrowingType, MyLess>;
10451c0b2f7Stbbdev
10551c0b2f7Stbbdev #if TBB_USE_EXCEPTIONS
test_exceptions()10651c0b2f7Stbbdev void test_exceptions() {
10751c0b2f7Stbbdev // TODO: TBB_USE_EXCEPTIONS?
10851c0b2f7Stbbdev const std::size_t TOO_LARGE_SZ = std::vector<MyThrowingType, typename CPQExTestType::allocator_type>{}.max_size() + 1;
10951c0b2f7Stbbdev
11051c0b2f7Stbbdev REQUIRE(TOO_LARGE_SZ < std::numeric_limits<std::size_t>::max());
11151c0b2f7Stbbdev MyThrowingType elem;
11251c0b2f7Stbbdev
11351c0b2f7Stbbdev // Allocation of empty queue should not throw
11451c0b2f7Stbbdev REQUIRE_NOTHROW([]{
11551c0b2f7Stbbdev MyThrowingType::throw_flag = 1;
11651c0b2f7Stbbdev CPQExTestType q;
11751c0b2f7Stbbdev }());
11851c0b2f7Stbbdev
11951c0b2f7Stbbdev // Allocation of small queue should not throw for reasonably sized type
12051c0b2f7Stbbdev REQUIRE_NOTHROW([]{
12151c0b2f7Stbbdev MyThrowingType::throw_flag = 1;
12251c0b2f7Stbbdev CPQExTestType(42);
12351c0b2f7Stbbdev }());
12451c0b2f7Stbbdev
12551c0b2f7Stbbdev // Allocate a queue with too large initial size
12651c0b2f7Stbbdev REQUIRE_THROWS([&]{
12751c0b2f7Stbbdev MyThrowingType::throw_flag = 0;
12851c0b2f7Stbbdev CPQExTestType q(TOO_LARGE_SZ);
12951c0b2f7Stbbdev }());
13051c0b2f7Stbbdev
13151c0b2f7Stbbdev // Test copy ctor exceptions
13251c0b2f7Stbbdev MyThrowingType::throw_flag = 0;
13351c0b2f7Stbbdev CPQExTestType src_q(42);
13451c0b2f7Stbbdev elem.priority = 42;
13551c0b2f7Stbbdev for (std::size_t i = 0; i < 42; ++i) src_q.push(elem);
13651c0b2f7Stbbdev
13751c0b2f7Stbbdev REQUIRE_THROWS_MESSAGE([&]{
13851c0b2f7Stbbdev MyThrowingType::throw_flag = 1;
13951c0b2f7Stbbdev CPQExTestType q(src_q);
14051c0b2f7Stbbdev }(), "Copy ctor did not throw exception");
14151c0b2f7Stbbdev
14251c0b2f7Stbbdev // Test assignment
14351c0b2f7Stbbdev MyThrowingType::throw_flag = 0;
14451c0b2f7Stbbdev CPQExTestType assign_q(24);
14551c0b2f7Stbbdev
14651c0b2f7Stbbdev REQUIRE_THROWS_MESSAGE([&]{
14751c0b2f7Stbbdev MyThrowingType::throw_flag = 1;
14851c0b2f7Stbbdev assign_q = src_q;
14951c0b2f7Stbbdev }(), "Assignment did not throw exception");
15051c0b2f7Stbbdev REQUIRE(assign_q.empty());
15151c0b2f7Stbbdev
15251c0b2f7Stbbdev for (std::size_t i = 0; i < push_selector_variants; ++i) {
15351c0b2f7Stbbdev MyThrowingType::throw_flag = 0;
15451c0b2f7Stbbdev CPQExTestType pq(3);
15551c0b2f7Stbbdev REQUIRE_NOTHROW([&]{
15651c0b2f7Stbbdev push_selector(pq, elem, i);
15751c0b2f7Stbbdev push_selector(pq, elem, i);
15851c0b2f7Stbbdev push_selector(pq, elem, i);
15951c0b2f7Stbbdev }());
16051c0b2f7Stbbdev
16151c0b2f7Stbbdev try {
16251c0b2f7Stbbdev MyThrowingType::throw_flag = 1;
16351c0b2f7Stbbdev push_selector(pq, elem, i);
16451c0b2f7Stbbdev } catch(...) {
16551c0b2f7Stbbdev REQUIRE_MESSAGE(!pq.empty(), "Failed: pq should not be empty");
16651c0b2f7Stbbdev REQUIRE_MESSAGE(pq.size() == 3, "Failed: pq should contain only three elements");
16751c0b2f7Stbbdev REQUIRE_MESSAGE(pq.try_pop(elem), "Failed: pq is not functional");
16851c0b2f7Stbbdev }
16951c0b2f7Stbbdev
17051c0b2f7Stbbdev MyThrowingType::throw_flag = 0;
17151c0b2f7Stbbdev CPQExTestType pq2(3);
17251c0b2f7Stbbdev REQUIRE_NOTHROW([&]{
17351c0b2f7Stbbdev push_selector(pq2, elem, i);
17451c0b2f7Stbbdev push_selector(pq2, elem, i);
17551c0b2f7Stbbdev }());
17651c0b2f7Stbbdev
17751c0b2f7Stbbdev try {
17851c0b2f7Stbbdev MyThrowingType::throw_flag = 1;
17951c0b2f7Stbbdev push_selector(pq2, elem, i);
18051c0b2f7Stbbdev } catch(...) {
18151c0b2f7Stbbdev REQUIRE_MESSAGE(!pq2.empty(), "Failed: pq should not be empty");
18251c0b2f7Stbbdev REQUIRE_MESSAGE(pq2.size() == 2, "Failed: pq should contain only two elements");
18351c0b2f7Stbbdev REQUIRE_MESSAGE(pq2.try_pop(elem), "Failed: pq is not functional");
18451c0b2f7Stbbdev }
18551c0b2f7Stbbdev }
18651c0b2f7Stbbdev }
18751c0b2f7Stbbdev #endif
18851c0b2f7Stbbdev
test_scoped_allocator()18951c0b2f7Stbbdev void test_scoped_allocator() {
19051c0b2f7Stbbdev using allocator_data_type = AllocatorAwareData<std::scoped_allocator_adaptor<std::allocator<int>>>;
19151c0b2f7Stbbdev using basic_allocator_type = std::scoped_allocator_adaptor<std::allocator<allocator_data_type>>;
19251c0b2f7Stbbdev using allocator_type = std::allocator_traits<basic_allocator_type>::template rebind_alloc<allocator_data_type>;
19351c0b2f7Stbbdev using container_type = tbb::concurrent_priority_queue<allocator_data_type, std::less<allocator_data_type>, allocator_type>;
19451c0b2f7Stbbdev
19551c0b2f7Stbbdev allocator_type allocator;
19651c0b2f7Stbbdev allocator_data_type data1(1, allocator);
19751c0b2f7Stbbdev allocator_data_type data2(1, allocator);
19851c0b2f7Stbbdev
19951c0b2f7Stbbdev container_type c1(allocator);
20051c0b2f7Stbbdev container_type c2(allocator);
20151c0b2f7Stbbdev
20251c0b2f7Stbbdev allocator_data_type::activate();
20351c0b2f7Stbbdev
20451c0b2f7Stbbdev c1.push(data1);
20551c0b2f7Stbbdev c2.push(std::move(data2));
20651c0b2f7Stbbdev
20751c0b2f7Stbbdev // TODO: support uses allocator construction in this place
20851c0b2f7Stbbdev // c1.emplace(data1);
20951c0b2f7Stbbdev
21051c0b2f7Stbbdev c1 = c2;
21151c0b2f7Stbbdev c2 = std::move(c1);
21251c0b2f7Stbbdev
21351c0b2f7Stbbdev allocator_data_type::deactivate();
21451c0b2f7Stbbdev }
21551c0b2f7Stbbdev
21651c0b2f7Stbbdev // Testing concurrent_priority_queue with smart pointers and other special types
21751c0b2f7Stbbdev //! \brief \ref error_guessing
21851c0b2f7Stbbdev TEST_CASE("concurrent_priority_queue with smart_pointers") {
21951c0b2f7Stbbdev test_cpq_with_smart_pointers();
22051c0b2f7Stbbdev }
22151c0b2f7Stbbdev
22251c0b2f7Stbbdev //! Testing push-pop operations in concurrent_priority_queue with multithreading and specific value type
22351c0b2f7Stbbdev //! \brief \ref error_guessing
22451c0b2f7Stbbdev TEST_CASE("multithreading support in concurrent_priority_queue with specific value type") {
22551c0b2f7Stbbdev test_multithreading();
22651c0b2f7Stbbdev }
22751c0b2f7Stbbdev
22851c0b2f7Stbbdev #if TBB_USE_EXCEPTIONS
22951c0b2f7Stbbdev //! Testing exceptions support in concurrent_priority_queue
23051c0b2f7Stbbdev //! \brief \ref stress \ref error_guessing
23151c0b2f7Stbbdev TEST_CASE("exception handling in concurrent_priority_queue") {
23251c0b2f7Stbbdev test_exceptions();
23351c0b2f7Stbbdev }
23451c0b2f7Stbbdev #endif
23551c0b2f7Stbbdev
23651c0b2f7Stbbdev //! \brief \ref error_guessing
23751c0b2f7Stbbdev TEST_CASE("concurrent_priority_queue with std::scoped_allocator_adaptor") {
23851c0b2f7Stbbdev test_scoped_allocator();
23951c0b2f7Stbbdev }
240