From: khizmax Date: Sun, 7 Feb 2016 21:15:41 +0000 (+0300) Subject: Moved MichaelList unit test to gtest framework X-Git-Tag: v2.2.0~405 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=b06ffd06ea24731bf88f7a110f03b033c202c8d4;p=libcds.git Moved MichaelList unit test to gtest framework --- diff --git a/cds/intrusive/impl/michael_list.h b/cds/intrusive/impl/michael_list.h index c85ca20d..84f0b554 100644 --- a/cds/intrusive/impl/michael_list.h +++ b/cds/intrusive/impl/michael_list.h @@ -211,6 +211,8 @@ namespace cds { namespace intrusive { typedef typename gc::template guarded_ptr< value_type > guarded_ptr; ///< Guarded pointer + static CDS_CONSTEXPR const size_t c_nHazardPtrCount = 4; ///< Count of hazard pointer required for the algorithm + //@cond // Rebind traits (split-list support) template @@ -945,7 +947,6 @@ namespace cds { namespace intrusive { bool insert_at( atomic_node_ptr& refHead, value_type& val ) { node_type * pNode = node_traits::to_node_ptr( val ); - link_checker::is_empty( pNode ); position pos; while ( true ) { @@ -966,7 +967,6 @@ namespace cds { namespace intrusive { bool insert_at( atomic_node_ptr& refHead, value_type& val, Func f ) { node_type * pNode = node_traits::to_node_ptr( val ); - link_checker::is_empty( pNode ); position pos; while ( true ) { diff --git a/projects/Win/vc14/cds.sln b/projects/Win/vc14/cds.sln index 48067e57..9ea88592 100644 --- a/projects/Win/vc14/cds.sln +++ b/projects/Win/vc14/cds.sln @@ -191,6 +191,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest-pqueue", "gtest-pqueu EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest-queue", "gtest-queue.vcxproj", "{9EB8FAB6-78E8-48B6-9589-85985CE8D33D}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest-list", "gtest-list.vcxproj", "{83FC591C-2CA2-4631-AD13-218FF4C27692}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -489,6 +491,18 @@ Global {9EB8FAB6-78E8-48B6-9589-85985CE8D33D}.Release|Win32.Build.0 = Release|Win32 {9EB8FAB6-78E8-48B6-9589-85985CE8D33D}.Release|x64.ActiveCfg = Release|x64 {9EB8FAB6-78E8-48B6-9589-85985CE8D33D}.Release|x64.Build.0 = Release|x64 + {83FC591C-2CA2-4631-AD13-218FF4C27692}.Debug|Win32.ActiveCfg = Debug|Win32 + {83FC591C-2CA2-4631-AD13-218FF4C27692}.Debug|Win32.Build.0 = Debug|Win32 + {83FC591C-2CA2-4631-AD13-218FF4C27692}.Debug|x64.ActiveCfg = Debug|x64 + {83FC591C-2CA2-4631-AD13-218FF4C27692}.Debug|x64.Build.0 = Debug|x64 + {83FC591C-2CA2-4631-AD13-218FF4C27692}.DebugVLD|Win32.ActiveCfg = DebugVLD|Win32 + {83FC591C-2CA2-4631-AD13-218FF4C27692}.DebugVLD|Win32.Build.0 = DebugVLD|Win32 + {83FC591C-2CA2-4631-AD13-218FF4C27692}.DebugVLD|x64.ActiveCfg = DebugVLD|x64 + {83FC591C-2CA2-4631-AD13-218FF4C27692}.DebugVLD|x64.Build.0 = DebugVLD|x64 + {83FC591C-2CA2-4631-AD13-218FF4C27692}.Release|Win32.ActiveCfg = Release|Win32 + {83FC591C-2CA2-4631-AD13-218FF4C27692}.Release|Win32.Build.0 = Release|Win32 + {83FC591C-2CA2-4631-AD13-218FF4C27692}.Release|x64.ActiveCfg = Release|x64 + {83FC591C-2CA2-4631-AD13-218FF4C27692}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -519,6 +533,7 @@ Global {EA5D825A-83A4-4A36-83C1-3D048D21D55B} = {810490B7-31E5-49AE-8455-CAF99A9658B6} {ED94B1D1-2442-43C2-A71C-A757122408A6} = {810490B7-31E5-49AE-8455-CAF99A9658B6} {9EB8FAB6-78E8-48B6-9589-85985CE8D33D} = {810490B7-31E5-49AE-8455-CAF99A9658B6} + {83FC591C-2CA2-4631-AD13-218FF4C27692} = {810490B7-31E5-49AE-8455-CAF99A9658B6} EndGlobalSection GlobalSection(DPCodeReviewSolutionGUID) = preSolution DPCodeReviewSolutionGUID = {00000000-0000-0000-0000-000000000000} diff --git a/projects/Win/vc14/gtest-list.vcxproj b/projects/Win/vc14/gtest-list.vcxproj new file mode 100644 index 00000000..19817ab5 --- /dev/null +++ b/projects/Win/vc14/gtest-list.vcxproj @@ -0,0 +1,242 @@ + + + + + DebugVLD + Win32 + + + DebugVLD + x64 + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + + + + + + + {83FC591C-2CA2-4631-AD13-218FF4C27692} + Win32Proj + list + 8.1 + + + + Application + true + v140 + Unicode + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + Application + true + v140 + Unicode + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)..\..\..\bin\vc.$(PlatformToolset)\$(Platform)\ + $(SolutionDir)..\..\..\obj\vc.$(PlatformToolset)\$(Platform)\$(ProjectName)\$(Configuration)\ + $(ProjectName)_d + + + true + $(SolutionDir)..\..\..\bin\vc.$(PlatformToolset)\$(Platform)\ + $(SolutionDir)..\..\..\obj\vc.$(PlatformToolset)\$(Platform)\$(ProjectName)\$(Configuration)\ + $(ProjectName)_d + + + true + $(SolutionDir)..\..\..\bin\vc.$(PlatformToolset)\$(Platform)\ + $(SolutionDir)..\..\..\obj\vc.$(PlatformToolset)\$(Platform)\$(ProjectName)\$(Configuration)\ + $(ProjectName)_d + + + true + $(SolutionDir)..\..\..\bin\vc.$(PlatformToolset)\$(Platform)\ + $(SolutionDir)..\..\..\obj\vc.$(PlatformToolset)\$(Platform)\$(ProjectName)\$(Configuration)\ + $(ProjectName)_d + + + false + $(SolutionDir)..\..\..\bin\vc.$(PlatformToolset)\$(Platform)-release\ + $(SolutionDir)..\..\..\obj\vc.$(PlatformToolset)\$(Platform)\$(ProjectName)\$(Configuration)\ + + + false + $(SolutionDir)..\..\..\bin\vc.$(PlatformToolset)\$(Platform)-release\ + $(SolutionDir)..\..\..\obj\vc.$(PlatformToolset)\$(Platform)\$(ProjectName)\$(Configuration)\ + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(BOOST_PATH);%(AdditionalIncludeDirectories) + + + Console + true + $(GTEST_LIB32);$(GTEST_ROOT)/lib/x86;$(BOOST_PATH)/stage32/lib;$(BOOST_PATH)/stage/lib;$(BOOST_PATH)/bin;%(AdditionalLibraryDirectories);$(OutDir) + gtestd.lib;%(AdditionalDependencies) + + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(BOOST_PATH);%(AdditionalIncludeDirectories) + + + Console + true + $(GTEST_LIB32);$(GTEST_ROOT)/lib/x86;$(BOOST_PATH)/stage32/lib;$(BOOST_PATH)/stage/lib;$(BOOST_PATH)/bin;%(AdditionalLibraryDirectories);$(OutDir) + gtestd.lib;%(AdditionalDependencies) + + + + + NotUsing + Level3 + Disabled + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(BOOST_PATH);%(AdditionalIncludeDirectories) + + + Console + true + $(GTEST_LIB64);$(GTEST_ROOT)/lib/x64;$(BOOST_PATH)/stage64/lib;$(BOOST_PATH)/bin;%(AdditionalLibraryDirectories);$(OutDir) + gtestd.lib;%(AdditionalDependencies) + + + + + NotUsing + Level3 + Disabled + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(BOOST_PATH);%(AdditionalIncludeDirectories) + + + Console + true + $(GTEST_LIB64);$(GTEST_ROOT)/lib/x64;$(BOOST_PATH)/stage64/lib;$(BOOST_PATH)/bin;%(AdditionalLibraryDirectories);$(OutDir) + gtestd.lib;%(AdditionalDependencies) + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(BOOST_PATH);%(AdditionalIncludeDirectories) + + + Console + true + true + true + $(GTEST_LIB32);$(GTEST_ROOT)/lib/x86;$(BOOST_PATH)/stage32/lib;$(BOOST_PATH)/stage/lib;$(BOOST_PATH)/bin;%(AdditionalLibraryDirectories);$(OutDir) + gtest.lib;%(AdditionalDependencies) + + + + + Level3 + NotUsing + MaxSpeed + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(BOOST_PATH);%(AdditionalIncludeDirectories) + + + Console + true + true + true + $(GTEST_LIB64);$(GTEST_ROOT)/lib/x64;$(BOOST_PATH)/stage64/lib;$(BOOST_PATH)/bin;%(AdditionalLibraryDirectories);$(OutDir) + gtest.lib;%(AdditionalDependencies) + + + + + + \ No newline at end of file diff --git a/projects/Win/vc14/gtest-list.vcxproj.filters b/projects/Win/vc14/gtest-list.vcxproj.filters new file mode 100644 index 00000000..1d995ef2 --- /dev/null +++ b/projects/Win/vc14/gtest-list.vcxproj.filters @@ -0,0 +1,36 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index 236e738e..42d34b89 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -1,4 +1,5 @@ add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/deque) +add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/list) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/pqueue) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/queue) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/stack) diff --git a/test/unit/list/CMakeLists.txt b/test/unit/list/CMakeLists.txt new file mode 100644 index 00000000..e3d3324e --- /dev/null +++ b/test/unit/list/CMakeLists.txt @@ -0,0 +1,22 @@ +set(PACKAGE_NAME unit-list) + +set(CDSGTEST_LIST_SOURCES + ../main.cpp + intrusive_michael_hp.cpp + intrusive_michael_dhp.cpp +) + +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR} +) + +add_executable(${PACKAGE_NAME} ${CDSGTEST_LIST_SOURCES}) +target_link_libraries(${PACKAGE_NAME} + ${CDS_SHARED_LIBRARY} + ${GTEST_LIBRARY} + ${Boost_THREAD_LIBRARY} + ${Boost_SYSTEM_LIBRARY} + ${CMAKE_THREAD_LIBS_INIT} +) + +add_test(NAME ${PACKAGE_NAME} COMMAND ${PACKAGE_NAME} WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH}) \ No newline at end of file diff --git a/test/unit/list/intrusive_michael_dhp.cpp b/test/unit/list/intrusive_michael_dhp.cpp new file mode 100644 index 00000000..7a33a83b --- /dev/null +++ b/test/unit/list/intrusive_michael_dhp.cpp @@ -0,0 +1,234 @@ +/* + This file is a part of libcds - Concurrent Data Structures library + + (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016 + + Source code repo: http://github.com/khizmax/libcds/ + Download: http://sourceforge.net/projects/libcds/files/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "test_intrusive_list_hp.h" +#include + +namespace { + namespace ci = cds::intrusive; + typedef cds::gc::DHP gc_type; + + class IntrusiveMichaelList_DHP : public cds_test::intrusive_list_hp + { + public: + typedef cds_test::intrusive_list_hp::base_item< ci::michael_list::node< gc_type>> base_item; + typedef cds_test::intrusive_list_hp::member_item< ci::michael_list::node< gc_type>> member_item; + + protected: + void SetUp() + { + struct traits: public ci::michael_list::traits + { + typedef ci::michael_list::base_hook< cds::opt::gc< gc_type >> hook; + }; + typedef ci::MichaelList< gc_type, base_item, traits > list_type; + + cds::gc::dhp::GarbageCollector::Construct( 16, list_type::c_nHazardPtrCount ); + cds::threading::Manager::attachThread(); + } + + void TearDown() + { + cds::threading::Manager::detachThread(); + cds::gc::hp::GarbageCollector::Destruct(); + } + }; + + TEST_F( IntrusiveMichaelList_DHP, base_hook ) + { + typedef ci::MichaelList< gc_type, base_item, + typename ci::michael_list::make_traits< + ci::opt::hook< ci::michael_list::base_hook< cds::opt::gc< gc_type >>> + ,ci::opt::disposer< mock_disposer > + ,cds::opt::less< less< base_item >> + >::type + > list_type; + + list_type l; + test_common( l ); + test_sorted_iterator( l ); + test_hp( l ); + } + + TEST_F( IntrusiveMichaelList_DHP, base_hook_cmp ) + { + typedef ci::MichaelList< gc_type, base_item, + typename ci::michael_list::make_traits< + ci::opt::hook< ci::michael_list::base_hook< cds::opt::gc< gc_type >>> + , ci::opt::disposer< mock_disposer > + , cds::opt::compare< cmp< base_item >> + >::type + > list_type; + + list_type l; + test_common( l ); + test_sorted_iterator( l ); + test_hp( l ); + } + + TEST_F( IntrusiveMichaelList_DHP, base_hook_item_counting ) + { + struct traits : public ci::michael_list::traits { + typedef ci::michael_list::base_hook< cds::opt::gc< gc_type >> hook; + typedef mock_disposer disposer; + typedef cmp< base_item > compare; + typedef intrusive_list_common::less< base_item > less; + typedef cds::atomicity::item_counter item_counter; + }; + typedef ci::MichaelList< gc_type, base_item, traits > list_type; + + list_type l; + test_common( l ); + test_sorted_iterator( l ); + test_hp( l ); + } + + TEST_F( IntrusiveMichaelList_DHP, base_hook_backoff ) + { + struct traits : public ci::michael_list::traits { + typedef ci::michael_list::base_hook< cds::opt::gc< gc_type >> hook; + typedef mock_disposer disposer; + typedef cmp< base_item > compare; + typedef intrusive_list_common::less< base_item > less; + typedef cds::atomicity::item_counter item_counter; + typedef cds::backoff::pause back_off; + }; + typedef ci::MichaelList< gc_type, base_item, traits > list_type; + + list_type l; + test_common( l ); + test_sorted_iterator( l ); + test_hp( l ); + } + + TEST_F( IntrusiveMichaelList_DHP, base_hook_seqcst ) + { + struct traits : public ci::michael_list::traits { + typedef ci::michael_list::base_hook< cds::opt::gc< gc_type >> hook; + typedef mock_disposer disposer; + typedef cmp< base_item > compare; + typedef intrusive_list_common::less< base_item > less; + typedef cds::atomicity::item_counter item_counter; + typedef cds::opt::v::sequential_consistent memory_model; + }; + typedef ci::MichaelList< gc_type, base_item, traits > list_type; + + list_type l; + test_common( l ); + test_sorted_iterator( l ); + test_hp( l ); + } + + TEST_F( IntrusiveMichaelList_DHP, member_hook ) + { + typedef ci::MichaelList< gc_type, member_item, + typename ci::michael_list::make_traits< + ci::opt::hook< ci::michael_list::member_hook< offsetof( member_item, hMember ), cds::opt::gc< gc_type >>> + ,ci::opt::disposer< mock_disposer > + ,cds::opt::less< less< member_item >> + >::type + > list_type; + + list_type l; + test_common( l ); + test_sorted_iterator( l ); + test_hp( l ); + } + + TEST_F( IntrusiveMichaelList_DHP, member_hook_cmp ) + { + typedef ci::MichaelList< gc_type, member_item, + typename ci::michael_list::make_traits< + ci::opt::hook< ci::michael_list::member_hook< offsetof( member_item, hMember ), cds::opt::gc< gc_type >>> + ,ci::opt::disposer< mock_disposer > + ,cds::opt::compare< cmp< member_item >> + >::type + > list_type; + + list_type l; + test_common( l ); + test_sorted_iterator( l ); + test_hp( l ); + } + + TEST_F( IntrusiveMichaelList_DHP, member_hook_item_counting ) + { + struct traits : public ci::michael_list::traits { + typedef ci::michael_list::member_hook< offsetof( member_item, hMember ), cds::opt::gc< gc_type >> hook; + typedef mock_disposer disposer; + typedef cmp< member_item > compare; + typedef intrusive_list_common::less< member_item > less; + typedef cds::atomicity::item_counter item_counter; + }; + typedef ci::MichaelList< gc_type, member_item, traits > list_type; + + list_type l; + test_common( l ); + test_sorted_iterator( l ); + test_hp( l ); + } + + TEST_F( IntrusiveMichaelList_DHP, member_hook_seqcst ) + { + struct traits : public ci::michael_list::traits { + typedef ci::michael_list::member_hook< offsetof( member_item, hMember ), cds::opt::gc< gc_type >> hook; + typedef mock_disposer disposer; + typedef cmp< member_item > compare; + typedef intrusive_list_common::less< member_item > less; + typedef cds::atomicity::item_counter item_counter; + typedef cds::opt::v::sequential_consistent memory_model; + }; + typedef ci::MichaelList< gc_type, member_item, traits > list_type; + + list_type l; + test_common( l ); + test_sorted_iterator( l ); + test_hp( l ); + } + + TEST_F( IntrusiveMichaelList_DHP, member_hook_back_off ) + { + struct traits : public ci::michael_list::traits { + typedef ci::michael_list::member_hook< offsetof( member_item, hMember ), cds::opt::gc< gc_type >> hook; + typedef mock_disposer disposer; + typedef cmp< member_item > compare; + typedef intrusive_list_common::less< member_item > less; + typedef cds::atomicity::item_counter item_counter; + typedef cds::backoff::empty back_off; + }; + typedef ci::MichaelList< gc_type, member_item, traits > list_type; + + list_type l; + test_common( l ); + test_sorted_iterator( l ); + test_hp( l ); + } + +} // namespace diff --git a/test/unit/list/intrusive_michael_hp.cpp b/test/unit/list/intrusive_michael_hp.cpp new file mode 100644 index 00000000..2436f18e --- /dev/null +++ b/test/unit/list/intrusive_michael_hp.cpp @@ -0,0 +1,235 @@ +/* + This file is a part of libcds - Concurrent Data Structures library + + (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016 + + Source code repo: http://github.com/khizmax/libcds/ + Download: http://sourceforge.net/projects/libcds/files/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "test_intrusive_list_hp.h" +#include + +namespace { + namespace ci = cds::intrusive; + typedef cds::gc::HP gc_type; + + class IntrusiveMichaelList_HP : public cds_test::intrusive_list_hp + { + public: + typedef cds_test::intrusive_list_hp::base_item< ci::michael_list::node< gc_type>> base_item; + typedef cds_test::intrusive_list_hp::member_item< ci::michael_list::node< gc_type>> member_item; + + protected: + void SetUp() + { + struct traits: public ci::michael_list::traits + { + typedef ci::michael_list::base_hook< cds::opt::gc< gc_type >> hook; + }; + typedef ci::MichaelList< gc_type, base_item, traits > list_type; + + // +1 - for guarded_ptr + cds::gc::hp::GarbageCollector::Construct( list_type::c_nHazardPtrCount + 1, 1, 16 ); + cds::threading::Manager::attachThread(); + } + + void TearDown() + { + cds::threading::Manager::detachThread(); + cds::gc::hp::GarbageCollector::Destruct( true ); + } + }; + + TEST_F( IntrusiveMichaelList_HP, base_hook ) + { + typedef ci::MichaelList< gc_type, base_item, + typename ci::michael_list::make_traits< + ci::opt::hook< ci::michael_list::base_hook< cds::opt::gc< gc_type >>> + ,ci::opt::disposer< mock_disposer > + ,cds::opt::less< less< base_item >> + >::type + > list_type; + + list_type l; + test_common( l ); + test_sorted_iterator( l ); + test_hp( l ); + } + + TEST_F( IntrusiveMichaelList_HP, base_hook_cmp ) + { + typedef ci::MichaelList< gc_type, base_item, + typename ci::michael_list::make_traits< + ci::opt::hook< ci::michael_list::base_hook< cds::opt::gc< gc_type >>> + , ci::opt::disposer< mock_disposer > + , cds::opt::compare< cmp< base_item >> + >::type + > list_type; + + list_type l; + test_common( l ); + test_sorted_iterator( l ); + test_hp( l ); + } + + TEST_F( IntrusiveMichaelList_HP, base_hook_item_counting ) + { + struct traits : public ci::michael_list::traits { + typedef ci::michael_list::base_hook< cds::opt::gc< gc_type >> hook; + typedef mock_disposer disposer; + typedef cmp< base_item > compare; + typedef intrusive_list_common::less< base_item > less; + typedef cds::atomicity::item_counter item_counter; + }; + typedef ci::MichaelList< gc_type, base_item, traits > list_type; + + list_type l; + test_common( l ); + test_sorted_iterator( l ); + test_hp( l ); + } + + TEST_F( IntrusiveMichaelList_HP, base_hook_backoff ) + { + struct traits : public ci::michael_list::traits { + typedef ci::michael_list::base_hook< cds::opt::gc< gc_type >> hook; + typedef mock_disposer disposer; + typedef cmp< base_item > compare; + typedef intrusive_list_common::less< base_item > less; + typedef cds::atomicity::item_counter item_counter; + typedef cds::backoff::pause back_off; + }; + typedef ci::MichaelList< gc_type, base_item, traits > list_type; + + list_type l; + test_common( l ); + test_sorted_iterator( l ); + test_hp( l ); + } + + TEST_F( IntrusiveMichaelList_HP, base_hook_seqcst ) + { + struct traits : public ci::michael_list::traits { + typedef ci::michael_list::base_hook< cds::opt::gc< gc_type >> hook; + typedef mock_disposer disposer; + typedef cmp< base_item > compare; + typedef intrusive_list_common::less< base_item > less; + typedef cds::atomicity::item_counter item_counter; + typedef cds::opt::v::sequential_consistent memory_model; + }; + typedef ci::MichaelList< gc_type, base_item, traits > list_type; + + list_type l; + test_common( l ); + test_sorted_iterator( l ); + test_hp( l ); + } + + TEST_F( IntrusiveMichaelList_HP, member_hook ) + { + typedef ci::MichaelList< gc_type, member_item, + typename ci::michael_list::make_traits< + ci::opt::hook< ci::michael_list::member_hook< offsetof( member_item, hMember ), cds::opt::gc< gc_type >>> + ,ci::opt::disposer< mock_disposer > + ,cds::opt::less< less< member_item >> + >::type + > list_type; + + list_type l; + test_common( l ); + test_sorted_iterator( l ); + test_hp( l ); + } + + TEST_F( IntrusiveMichaelList_HP, member_hook_cmp ) + { + typedef ci::MichaelList< gc_type, member_item, + typename ci::michael_list::make_traits< + ci::opt::hook< ci::michael_list::member_hook< offsetof( member_item, hMember ), cds::opt::gc< gc_type >>> + ,ci::opt::disposer< mock_disposer > + ,cds::opt::compare< cmp< member_item >> + >::type + > list_type; + + list_type l; + test_common( l ); + test_sorted_iterator( l ); + test_hp( l ); + } + + TEST_F( IntrusiveMichaelList_HP, member_hook_item_counting ) + { + struct traits : public ci::michael_list::traits { + typedef ci::michael_list::member_hook< offsetof( member_item, hMember ), cds::opt::gc< gc_type >> hook; + typedef mock_disposer disposer; + typedef cmp< member_item > compare; + typedef intrusive_list_common::less< member_item > less; + typedef cds::atomicity::item_counter item_counter; + }; + typedef ci::MichaelList< gc_type, member_item, traits > list_type; + + list_type l; + test_common( l ); + test_sorted_iterator( l ); + test_hp( l ); + } + + TEST_F( IntrusiveMichaelList_HP, member_hook_seqcst ) + { + struct traits : public ci::michael_list::traits { + typedef ci::michael_list::member_hook< offsetof( member_item, hMember ), cds::opt::gc< gc_type >> hook; + typedef mock_disposer disposer; + typedef cmp< member_item > compare; + typedef intrusive_list_common::less< member_item > less; + typedef cds::atomicity::item_counter item_counter; + typedef cds::opt::v::sequential_consistent memory_model; + }; + typedef ci::MichaelList< gc_type, member_item, traits > list_type; + + list_type l; + test_common( l ); + test_sorted_iterator( l ); + test_hp( l ); + } + + TEST_F( IntrusiveMichaelList_HP, member_hook_back_off ) + { + struct traits : public ci::michael_list::traits { + typedef ci::michael_list::member_hook< offsetof( member_item, hMember ), cds::opt::gc< gc_type >> hook; + typedef mock_disposer disposer; + typedef cmp< member_item > compare; + typedef intrusive_list_common::less< member_item > less; + typedef cds::atomicity::item_counter item_counter; + typedef cds::backoff::empty back_off; + }; + typedef ci::MichaelList< gc_type, member_item, traits > list_type; + + list_type l; + test_common( l ); + test_sorted_iterator( l ); + test_hp( l ); + } + +} // namespace diff --git a/test/unit/list/test_intrusive_list.h b/test/unit/list/test_intrusive_list.h new file mode 100644 index 00000000..65130c59 --- /dev/null +++ b/test/unit/list/test_intrusive_list.h @@ -0,0 +1,506 @@ +/* + This file is a part of libcds - Concurrent Data Structures library + + (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016 + + Source code repo: http://github.com/khizmax/libcds/ + Download: http://sourceforge.net/projects/libcds/files/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef CDSUNIT_LIST_TEST_INTRUSIVE_LIST_H +#define CDSUNIT_LIST_TEST_INTRUSIVE_LIST_H + +#include +#include + +namespace cds_test { + + class intrusive_list_common : public fixture + { + public: + struct stat { + int nDisposeCount; + int nUpdateExistsCall; + int nUpdateNewCall; + int nFindCall; + int nEraseCall; + int nInsertCall; + + stat() + : nDisposeCount( 0 ) + , nUpdateExistsCall( 0 ) + , nUpdateNewCall( 0 ) + , nFindCall( 0 ) + , nEraseCall( 0 ) + , nInsertCall( 0 ) + {} + + stat( const stat& s ) + { + *this = s; + } + + stat& operator =( const stat& s ) + { + memcpy( this, &s, sizeof( s ) ); + return *this; + } + }; + + template + struct base_item : public Node + { + int nKey; + int nVal; + + mutable stat s; + + base_item() + {} + + base_item( int key, int val ) + : nKey( key ) + , nVal( val ) + , s() + {} + + base_item( const base_item& v ) + : nKey( v.nKey ) + , nVal( v.nVal ) + , s() + {} + + const int& key() const + { + return nKey; + } + + base_item& operator=( base_item const& src ) + { + nKey = src.nKey; + nVal = src.nVal; + return *this; + } + + base_item& operator=( base_item&& src ) + { + nKey = src.nKey; + nVal = src.nVal; + return *this; + } + }; + + template + struct member_item + { + int nKey; + int nVal; + Node hMember; + mutable stat s; + + member_item() + {} + + member_item( int key, int val ) + : nKey( key ) + , nVal( val ) + , s() + {} + + member_item( const member_item& v ) + : nKey( v.nKey ) + , nVal( v.nVal ) + , s() + {} + + const int& key() const + { + return nKey; + } + + member_item& operator =( member_item const& src ) + { + nKey = src.nKey; + nVal = src.nVal; + return *this; + } + + member_item& operator=( member_item&& src ) + { + nKey = src.nKey; + nVal = src.nVal; + return *this; + } + }; + + template + struct less + { + bool operator ()( const T& v1, const T& v2 ) const + { + return v1.key() < v2.key(); + } + + template + bool operator ()( const T& v1, const Q& v2 ) const + { + return v1.key() < v2; + } + + template + bool operator ()( const Q& v1, const T& v2 ) const + { + return v1 < v2.key(); + } + }; + + struct other_item { + int nKey; + + other_item( int n ) + : nKey( n ) + {} + }; + + struct other_less { + template + bool operator()( T const& i1, Q const& i2 ) const + { + return i1.nKey < i2.nKey; + } + }; + + template + struct cmp { + int operator ()( const T& v1, const T& v2 ) const + { + if ( v1.key() < v2.key() ) + return -1; + return v1.key() > v2.key() ? 1 : 0; + } + + template + int operator ()( const T& v1, const Q& v2 ) const + { + if ( v1.key() < v2 ) + return -1; + return v1.key() > v2 ? 1 : 0; + } + + template + int operator ()( const Q& v1, const T& v2 ) const + { + if ( v1 < v2.key() ) + return -1; + return v1 > v2.key() ? 1 : 0; + } + }; + + struct mock_disposer + { + template + void operator ()( T * p ) + { + ++p->s.nDisposeCount; + } + }; + + struct update_functor + { + template + void operator ()( bool bNew, T& item, T& /*val*/ ) + { + if ( bNew ) + ++item.s.nUpdateNewCall; + else + ++item.s.nUpdateExistsCall; + } + }; + + struct find_functor + { + template + void operator ()( T& item, Q& /*val*/ ) + { + ++item.s.nFindCall; + } + }; + + struct erase_functor + { + template + void operator()( T const& item ) + { + item.s.nEraseCall++; + } + }; + + protected: + template + void test_common( List& l ) + { + // Precondition: list is empty + // Postcondition: list is empty + + static const size_t nSize = 20; + typedef typename List::value_type value_type; + value_type arr[ nSize ]; + + for ( size_t i = 0; i < nSize; ++i ) { + arr[i].nKey = static_cast( i ); + arr[i].nVal = arr[i].nKey * 10; + } + shuffle( arr, arr + nSize ); + + ASSERT_TRUE( l.empty() ); + ASSERT_CONTAINER_SIZE( l, 0 ); + + // insert / find + for ( auto& i : arr ) { + EXPECT_FALSE( l.contains( i.nKey )); + EXPECT_FALSE( l.contains( other_item( i.nKey ), other_less())); + EXPECT_FALSE( l.find( i.nKey, []( value_type& item, int ) { ++item.s.nFindCall; } )); + EXPECT_EQ( i.s.nFindCall, 0 ); + EXPECT_FALSE( l.find_with( other_item( i.nKey ), other_less(), []( value_type& item, other_item const& ) { ++item.s.nFindCall; } )); + EXPECT_EQ( i.s.nFindCall, 0 ); + + if ( i.nKey & 1 ) + EXPECT_TRUE( l.insert( i )); + else { + EXPECT_EQ( i.s.nInsertCall, 0 ); + EXPECT_TRUE( l.insert( i, []( value_type& i ) { ++i.s.nInsertCall; } )); + EXPECT_EQ( i.s.nInsertCall, 1 ); + } + + EXPECT_TRUE( l.contains( i.nKey )); + EXPECT_TRUE( l.contains( i )); + EXPECT_TRUE( l.contains( other_item( i.nKey ), other_less())); + EXPECT_TRUE( l.find( i.nKey, []( value_type& item, int ) { ++item.s.nFindCall; } )); + EXPECT_EQ( i.s.nFindCall, 1 ); + EXPECT_TRUE( l.find( i, []( value_type& item, value_type const& ) { ++item.s.nFindCall; } )); + EXPECT_EQ( i.s.nFindCall, 2 ); + EXPECT_TRUE( l.find_with( other_item( i.nKey ), other_less(), []( value_type& item, other_item const& ) { ++item.s.nFindCall; } )); + EXPECT_EQ( i.s.nFindCall, 3 ); + + EXPECT_FALSE( l.insert( i ) ); + ASSERT_FALSE( l.empty() ); + } + ASSERT_CONTAINER_SIZE( l, nSize ); + + // check all items + for ( auto const& i : arr ) { + EXPECT_TRUE( l.contains( i.nKey )); + EXPECT_TRUE( l.contains( i )); + EXPECT_TRUE( l.contains( other_item( i.nKey ), other_less())); + EXPECT_TRUE( l.find( i.nKey, []( value_type& item, int ) { ++item.s.nFindCall; } )); + EXPECT_EQ( i.s.nFindCall, 4 ); + EXPECT_TRUE( l.find( i, []( value_type& item, value_type const& ) { ++item.s.nFindCall; } )); + EXPECT_EQ( i.s.nFindCall, 5 ); + EXPECT_TRUE( l.find_with( other_item( i.nKey ), other_less(), []( value_type& item, other_item const& ) { ++item.s.nFindCall; } )); + EXPECT_EQ( i.s.nFindCall, 6 ); + } + ASSERT_FALSE( l.empty() ); + ASSERT_CONTAINER_SIZE( l, nSize ); + + // update existing test + for ( auto& i : arr ) { + EXPECT_EQ( i.s.nUpdateExistsCall, 0 ); + std::pair ret = l.update( i, update_functor() ); + EXPECT_TRUE( ret.first ); + EXPECT_FALSE( ret.second ); + EXPECT_EQ( i.s.nUpdateExistsCall, 1 ); + + ret = l.update( i, []( bool bNew, value_type& i, value_type& arg ) { + EXPECT_FALSE( bNew ); + EXPECT_EQ( i.s.nUpdateExistsCall, 1 ); + EXPECT_TRUE( &i == &arg ); + ++i.s.nUpdateExistsCall; + }); + EXPECT_TRUE( ret.first ); + EXPECT_FALSE( ret.second ); + EXPECT_EQ( i.s.nUpdateExistsCall, 2 ); + } + + // erase test + for ( auto const& i : arr ) { + if ( i.nKey & 1 ) + EXPECT_TRUE( l.erase( i.nKey )); + else + EXPECT_TRUE( l.erase_with( other_item( i.nKey ), other_less() )); + + EXPECT_FALSE( l.contains( i )); + } + EXPECT_TRUE( l.empty() ); + EXPECT_CONTAINER_SIZE( l, 0 ); + + // Apply retired pointer to clean links + List::gc::force_dispose(); + + for ( auto const& i : arr ) + EXPECT_EQ( i.s.nDisposeCount, 1 ); + + // erase with functor + for ( auto& i : arr ) { + std::pair ret = l.update( i, update_functor(), false ); + EXPECT_FALSE( ret.first ); + EXPECT_FALSE( ret.second ); + + ret = l.update( i, update_functor(), true ); + EXPECT_TRUE( ret.first ); + EXPECT_TRUE( ret.second ); + EXPECT_EQ( i.s.nUpdateNewCall, 1 ); + } + EXPECT_FALSE( l.empty() ); + EXPECT_CONTAINER_SIZE( l, nSize ); + + for ( auto const& i : arr ) { + EXPECT_EQ( i.s.nEraseCall, 0 ); + if ( i.nKey & 1 ) { + EXPECT_TRUE( l.erase_with( other_item( i.nKey ), other_less(), erase_functor())); + EXPECT_FALSE( l.erase_with( other_item( i.nKey ), other_less(), erase_functor())); + } + else { + EXPECT_TRUE( l.erase( i.nKey, []( value_type& item) { ++item.s.nEraseCall; } )); + EXPECT_FALSE( l.erase( i.nKey, []( value_type& item) { ++item.s.nEraseCall; } )); + } + EXPECT_EQ( i.s.nEraseCall, 1 ); + EXPECT_FALSE( l.contains( i.nKey )); + } + EXPECT_TRUE( l.empty() ); + EXPECT_CONTAINER_SIZE( l, 0 ); + + // Apply retired pointer to clean links + List::gc::force_dispose(); + + for ( auto const& i : arr ) + EXPECT_EQ( i.s.nDisposeCount, 2 ); + + // clear test + for ( auto& i : arr ) + EXPECT_TRUE( l.insert( i )); + + EXPECT_FALSE( l.empty() ); + EXPECT_CONTAINER_SIZE( l, nSize ); + + l.clear(); + + EXPECT_TRUE( l.empty() ); + EXPECT_CONTAINER_SIZE( l, 0 ); + + // Apply retired pointer to clean links + List::gc::force_dispose(); + for ( auto const& i : arr ) { + EXPECT_EQ( i.s.nDisposeCount, 3 ); + EXPECT_FALSE( l.contains( i )); + } + + // unlink test + for ( auto& i : arr ) + EXPECT_TRUE( l.insert( i ) ); + for ( auto& i : arr ) { + value_type val( i ); + EXPECT_TRUE( l.contains( val )); + EXPECT_FALSE( l.unlink( val )); + EXPECT_TRUE( l.contains( val ) ); + EXPECT_TRUE( l.unlink( i )); + EXPECT_FALSE( l.unlink( i )); + EXPECT_FALSE( l.contains( i ) ); + } + EXPECT_TRUE( l.empty() ); + EXPECT_CONTAINER_SIZE( l, 0 ); + + // Apply retired pointer to clean links + List::gc::force_dispose(); + for ( auto const& i : arr ) { + EXPECT_EQ( i.s.nDisposeCount, 4 ); + EXPECT_FALSE( l.contains( i ) ); + } + + // Iterators on empty list + { + auto it = l.begin(); + auto itEnd = l.end(); + auto cit = l.cbegin(); + auto citEnd = l.cend(); + + EXPECT_TRUE( it == itEnd ); + EXPECT_TRUE( it == cit ); + EXPECT_TRUE( cit == citEnd ); + + ++it; + ++cit; + + EXPECT_TRUE( it == itEnd ); + EXPECT_TRUE( it == cit ); + EXPECT_TRUE( cit == citEnd ); + } + } + + template + void test_sorted_iterator( List& l ) + { + // Precondition: list is empty + // Postcondition: list is empty + + static const size_t nSize = 20; + typedef typename List::value_type value_type; + value_type arr[nSize]; + + for ( size_t i = 0; i < nSize; ++i ) { + arr[i].nKey = static_cast(i); + arr[i].nVal = arr[i].nKey * 10; + } + shuffle( arr, arr + nSize ); + + ASSERT_TRUE( l.empty() ); + ASSERT_CONTAINER_SIZE( l, 0 ); + + for ( auto& i : arr ) + EXPECT_TRUE( l.insert( i ) ); + + int key = 0; + for ( auto it = l.begin(); it != l.end(); ++it ) { + EXPECT_EQ( it->nKey, key ); + EXPECT_EQ( (*it).nKey, key ); + ++key; + } + + key = 0; + for ( auto it = l.cbegin(); it != l.cend(); ++it ) { + EXPECT_EQ( it->nKey, key ); + EXPECT_EQ( (*it).nKey, key ); + ++key; + } + + l.clear(); + List::gc::force_dispose(); + for ( auto const& i : arr ) { + EXPECT_EQ( i.s.nDisposeCount, 1 ); + EXPECT_FALSE( l.contains( i ) ); + } + } + }; + +} // namespace cds_test + +#endif // CDSUNIT_LIST_TEST_INTRUSIVE_LIST_H diff --git a/test/unit/list/test_intrusive_list_hp.h b/test/unit/list/test_intrusive_list_hp.h new file mode 100644 index 00000000..b5a95814 --- /dev/null +++ b/test/unit/list/test_intrusive_list_hp.h @@ -0,0 +1,110 @@ +/* + This file is a part of libcds - Concurrent Data Structures library + + (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016 + + Source code repo: http://github.com/khizmax/libcds/ + Download: http://sourceforge.net/projects/libcds/files/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef CDSUNIT_LIST_TEST_INTRUSIVE_LIST_HP_H +#define CDSUNIT_LIST_TEST_INTRUSIVE_LIST_HP_H + +#include "test_intrusive_list.h" + +namespace cds_test { + + class intrusive_list_hp : public intrusive_list_common + { + protected: + template + void test_hp( List& l ) + { + // Precondition: list is empty + // Postcondition: list is empty + + static const size_t nSize = 20; + typedef typename List::value_type value_type; + value_type arr[ nSize ]; + + for ( size_t i = 0; i < nSize; ++i ) { + arr[i].nKey = static_cast( i ); + arr[i].nVal = arr[i].nKey * 10; + } + shuffle( arr, arr + nSize ); + + typedef typename List::guarded_ptr guarded_ptr; + + ASSERT_TRUE( l.empty() ); + ASSERT_CONTAINER_SIZE( l, 0 ); + + guarded_ptr gp; + + // get() test + for ( auto& i : arr ) { + gp = l.get( i.nKey ); + EXPECT_TRUE( !gp ); + gp = l.get_with( other_item( i.nKey ), other_less()); + EXPECT_TRUE( !gp ); + + EXPECT_TRUE( l.insert( i )); + + gp = l.get( i.nKey ); + ASSERT_FALSE( !gp ); + EXPECT_EQ( gp->nKey, i.nKey ); + EXPECT_EQ( gp->nVal, i.nVal ); + gp = l.get_with( other_item( i.nKey ), other_less() ); + ASSERT_FALSE( !gp ); + EXPECT_EQ( gp->nKey, i.nKey ); + EXPECT_EQ( gp->nVal, i.nVal ); + } + + // extract() test + for ( int i = 0; i < static_cast(nSize); ++i ) { + if ( i & 1 ) + gp = l.extract( i ); + else + gp = l.extract_with( other_item(i), other_less()); + ASSERT_FALSE( !gp ); + EXPECT_EQ( gp->nKey, i ); + + gp = l.extract( i ); + EXPECT_TRUE( !gp ); + gp = l.extract_with( other_item( i ), other_less() ); + EXPECT_TRUE( !gp ); + } + + ASSERT_TRUE( l.empty() ); + ASSERT_CONTAINER_SIZE( l, 0 ); + + List::gc::force_dispose(); + for ( auto const& i : arr ) { + EXPECT_EQ( i.s.nDisposeCount, 1 ); + EXPECT_FALSE( l.contains( i ) ); + } + } + }; + +} // namespace cds_test + +#endif // CDSUNIT_LIST_TEST_INTRUSIVE_LIST_HP_H