xref: /oneTBB/test/tbb/test_intrusive_list.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 //! \file test_intrusive_list.cpp
1851c0b2f7Stbbdev //! \brief Test for [internal] functionality
1951c0b2f7Stbbdev 
2051c0b2f7Stbbdev #include "common/test.h"
2151c0b2f7Stbbdev #include "common/utils.h"
2251c0b2f7Stbbdev #include "../../src/tbb/intrusive_list.h"
2351c0b2f7Stbbdev 
2451c0b2f7Stbbdev using tbb::detail::r1::intrusive_list_node;
2551c0b2f7Stbbdev 
2651c0b2f7Stbbdev // Machine word filled with repeated pattern of FC bits
2751c0b2f7Stbbdev const uintptr_t NoliMeTangere = ~uintptr_t(0)/0xFF*0xFC;
2851c0b2f7Stbbdev 
2951c0b2f7Stbbdev struct VerificationBase : utils::NoAfterlife {
3051c0b2f7Stbbdev     uintptr_t m_Canary;
VerificationBaseVerificationBase3151c0b2f7Stbbdev     VerificationBase() : m_Canary(NoliMeTangere) {}
3251c0b2f7Stbbdev }; // struct VerificationBase
3351c0b2f7Stbbdev 
3451c0b2f7Stbbdev struct DataItemWithInheritedNodeBase : intrusive_list_node {
3551c0b2f7Stbbdev     int m_Data;
3651c0b2f7Stbbdev 
DataItemWithInheritedNodeBaseDataItemWithInheritedNodeBase3751c0b2f7Stbbdev     DataItemWithInheritedNodeBase( int value ) : m_Data(value) {}
3851c0b2f7Stbbdev 
DataDataItemWithInheritedNodeBase3951c0b2f7Stbbdev     int Data() const { return m_Data; }
4051c0b2f7Stbbdev }; // struct DataItemWithInheritedNodeBase
4151c0b2f7Stbbdev 
4251c0b2f7Stbbdev struct DataItemWithInheritedNode : VerificationBase, DataItemWithInheritedNodeBase {
4351c0b2f7Stbbdev     friend class tbb::detail::r1::intrusive_list<DataItemWithInheritedNode>;
4451c0b2f7Stbbdev 
DataItemWithInheritedNodeDataItemWithInheritedNode4551c0b2f7Stbbdev     DataItemWithInheritedNode( int value ) : DataItemWithInheritedNodeBase(value) {}
4651c0b2f7Stbbdev }; // struct DataItemWithInheritedNode
4751c0b2f7Stbbdev 
4851c0b2f7Stbbdev struct DataItemWithMemberNodeBase {
4951c0b2f7Stbbdev     int m_Data;
5051c0b2f7Stbbdev 
5151c0b2f7Stbbdev     // Cannot be used be member_intrusive_list to form lists of objects derived from DataItemBase
5251c0b2f7Stbbdev     intrusive_list_node m_BaseNode;
5351c0b2f7Stbbdev 
DataItemWithMemberNodeBaseDataItemWithMemberNodeBase5451c0b2f7Stbbdev     DataItemWithMemberNodeBase( int value ) : m_Data(value) {}
5551c0b2f7Stbbdev 
DataDataItemWithMemberNodeBase5651c0b2f7Stbbdev     int Data() const { return m_Data; }
5751c0b2f7Stbbdev }; // struct DataItemWithMemberNodeBase
5851c0b2f7Stbbdev 
5951c0b2f7Stbbdev struct DataItemWithMemberNodes : VerificationBase, DataItemWithMemberNodeBase {
6051c0b2f7Stbbdev     intrusive_list_node m_Node;
6151c0b2f7Stbbdev 
DataItemWithMemberNodesDataItemWithMemberNodes6251c0b2f7Stbbdev     DataItemWithMemberNodes( int value ) : DataItemWithMemberNodeBase(value) {}
6351c0b2f7Stbbdev }; // struct DataItemWithMemberNodes
6451c0b2f7Stbbdev 
6551c0b2f7Stbbdev using intrusive_list1 = tbb::detail::r1::intrusive_list<DataItemWithInheritedNode>;
6651c0b2f7Stbbdev using intrusive_list2 = tbb::detail::r1::memptr_intrusive_list<DataItemWithMemberNodes,
6751c0b2f7Stbbdev                                                                DataItemWithMemberNodeBase,
6851c0b2f7Stbbdev                                                                &DataItemWithMemberNodeBase::m_BaseNode>;
6951c0b2f7Stbbdev 
7051c0b2f7Stbbdev using intrusive_list3 = tbb::detail::r1::memptr_intrusive_list<DataItemWithMemberNodes,
7151c0b2f7Stbbdev                                                                DataItemWithMemberNodes,
7251c0b2f7Stbbdev                                                                &DataItemWithMemberNodes::m_Node>;
7351c0b2f7Stbbdev 
7451c0b2f7Stbbdev const int NumElements = 256 * 1024;
7551c0b2f7Stbbdev 
7651c0b2f7Stbbdev // Iterates through the list forward and backward checking the validity of values stored by the list nodes
7751c0b2f7Stbbdev template <typename List, typename Iterator>
check_list_nodes(List & il,int value_step)7851c0b2f7Stbbdev void check_list_nodes( List& il, int value_step ) {
7951c0b2f7Stbbdev     REQUIRE_MESSAGE(il.size() == unsigned(NumElements / value_step), "Wrong size of the list");
8051c0b2f7Stbbdev     REQUIRE_MESSAGE(!il.empty(), "Incorrect result of empty() or the list is corrupted");
8151c0b2f7Stbbdev 
8251c0b2f7Stbbdev     int i;
8351c0b2f7Stbbdev     Iterator it = il.begin();
8451c0b2f7Stbbdev 
8551c0b2f7Stbbdev     Iterator it_default;
8651c0b2f7Stbbdev     REQUIRE_MESSAGE(it_default != it, "Incorrect default constructed intrusive_list::iterator");
8751c0b2f7Stbbdev 
8851c0b2f7Stbbdev     for ( i = value_step - 1; it != il.end(); ++it, i += value_step ) {
8951c0b2f7Stbbdev         REQUIRE_MESSAGE(it->Data() == i, "Unexpected node value while iterating forward");
9051c0b2f7Stbbdev         REQUIRE_MESSAGE(it->m_Canary == NoliMeTangere, "Memory corruption");
9151c0b2f7Stbbdev     }
9251c0b2f7Stbbdev 
9351c0b2f7Stbbdev     REQUIRE_MESSAGE(i == NumElements + value_step - 1, "Wrong number of list elements while iterating forward");
9451c0b2f7Stbbdev     it = il.end();
9551c0b2f7Stbbdev 
9651c0b2f7Stbbdev     for ( i = NumElements - 1, it--; it != il.end(); --it, i -= value_step ) {
9751c0b2f7Stbbdev         REQUIRE_MESSAGE(it->Data() == i, "Unexpected node value while iterating backward");
9851c0b2f7Stbbdev         REQUIRE_MESSAGE(it->m_Canary == NoliMeTangere, "Memory corruption");
9951c0b2f7Stbbdev     }
10051c0b2f7Stbbdev     REQUIRE_MESSAGE(i == -1, "Wrong number of list elements while iterating backward");
10151c0b2f7Stbbdev }
10251c0b2f7Stbbdev 
10351c0b2f7Stbbdev template <typename List, typename Item>
test_list_operations()10451c0b2f7Stbbdev void test_list_operations() {
10551c0b2f7Stbbdev     using iterator = typename List::iterator;
10651c0b2f7Stbbdev 
10751c0b2f7Stbbdev     List il;
10851c0b2f7Stbbdev 
10951c0b2f7Stbbdev     for (int i = NumElements - 1; i >= 0; --i) {
11051c0b2f7Stbbdev         il.push_front(*new Item(i));
11151c0b2f7Stbbdev     }
11251c0b2f7Stbbdev     check_list_nodes<const List, typename List::const_iterator>(il, 1);
11351c0b2f7Stbbdev     iterator it = il.begin();
11451c0b2f7Stbbdev 
11551c0b2f7Stbbdev     for (;it != il.end(); ++it) {
11651c0b2f7Stbbdev         Item& item = *it;
11751c0b2f7Stbbdev         it = il.erase(it); // also advances the iterator
11851c0b2f7Stbbdev         delete &item;
11951c0b2f7Stbbdev     }
12051c0b2f7Stbbdev 
12151c0b2f7Stbbdev     check_list_nodes<List, iterator>(il, 2);
12251c0b2f7Stbbdev     for (it = il.begin(); it != il.end(); ++it) {
12351c0b2f7Stbbdev         Item& item = *it;
12451c0b2f7Stbbdev         il.remove(*it++); // extra advance here as well
12551c0b2f7Stbbdev         delete &item;
12651c0b2f7Stbbdev     }
12751c0b2f7Stbbdev 
12851c0b2f7Stbbdev     check_list_nodes<List, iterator>(il, 4);
12951c0b2f7Stbbdev     for (it = il.begin(); it != il.end();) {
13051c0b2f7Stbbdev         Item& item = *it++; // the iterator advances only here
13151c0b2f7Stbbdev         il.remove(item);
13251c0b2f7Stbbdev         delete &item;
13351c0b2f7Stbbdev     }
13451c0b2f7Stbbdev     REQUIRE_MESSAGE(il.size() == 0, "The list has wrong size or not all items were removed");
13551c0b2f7Stbbdev     REQUIRE_MESSAGE(il.empty(), "Incorrect result of empty() or not all items were removed");
13651c0b2f7Stbbdev }
13751c0b2f7Stbbdev 
13851c0b2f7Stbbdev // TODO: tests for intrusive_list assertions were not ported
13951c0b2f7Stbbdev 
14051c0b2f7Stbbdev //! \brief \ref error_guessing
14151c0b2f7Stbbdev TEST_CASE("Test tbb::detail::r1::intrusive_list operations") {
14251c0b2f7Stbbdev     test_list_operations<intrusive_list1, DataItemWithInheritedNode>();
14351c0b2f7Stbbdev }
14451c0b2f7Stbbdev 
14551c0b2f7Stbbdev //! \brief \ref error_guessing
14651c0b2f7Stbbdev TEST_CASE("Test tbb::detail::r1::memptr_intrusive_list operations") {
14751c0b2f7Stbbdev     test_list_operations<intrusive_list2, DataItemWithMemberNodes>();
14851c0b2f7Stbbdev     test_list_operations<intrusive_list3, DataItemWithMemberNodes>();
14951c0b2f7Stbbdev }
150