diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 19a0b203..f5bc4230 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,118 +33,118 @@ jobs: matrix: include: - toolset: gcc-5 - cxxstd: "11,14,1z" + cxxstd: "14,1z" os: ubuntu-22.04 container: ubuntu:16.04 install: g++-5 supported: true - toolset: gcc-6 - cxxstd: "11,14,1z" + cxxstd: "14,1z" os: ubuntu-22.04 container: ubuntu:16.04 install: g++-6 supported: true - toolset: gcc-7 - cxxstd: "11,14,17" + cxxstd: "14,17" os: ubuntu-22.04 container: ubuntu:18.04 install: g++-7 supported: true - toolset: gcc-8 - cxxstd: "11,14,17,2a" + cxxstd: "14,17,2a" os: ubuntu-22.04 container: ubuntu:18.04 install: g++-8 supported: true - toolset: gcc-9 - cxxstd: "11,14,17,2a" + cxxstd: "14,17,2a" os: ubuntu-22.04 container: ubuntu:18.04 install: g++-9 supported: true - toolset: gcc-10 - cxxstd: "11,14,17,2a" + cxxstd: "14,17,2a" os: ubuntu-22.04 install: g++-10 supported: true - toolset: gcc-11 - cxxstd: "11,14,17,20" + cxxstd: "14,17,20" os: ubuntu-22.04 install: g++-11 supported: true - toolset: gcc-12 - cxxstd: "11,14,17,20" + cxxstd: "14,17,20" os: ubuntu-22.04 install: g++-12 supported: true - toolset: gcc-13 - cxxstd: "11,14,17,20" + cxxstd: "14,17,20" os: ubuntu-22.04 install: g++-13 supported: true - toolset: clang install: clang-9 compiler: clang++-9 - cxxstd: "11,14,17" + cxxstd: "14,17" os: ubuntu-22.04 container: ubuntu:18.04 - toolset: clang install: clang-10 compiler: clang++-10 - cxxstd: "11,14,17,2a" + cxxstd: "14,17,2a" os: ubuntu-20.04 supported: true - toolset: clang install: clang-11 compiler: clang++-11 - cxxstd: "11,14,17,2a" + cxxstd: "14,17,2a" os: ubuntu-20.04 supported: true - toolset: clang install: clang-12 compiler: clang++-12 - cxxstd: "11,14,17,20" + cxxstd: "14,17,20" os: ubuntu-22.04 supported: true - toolset: clang install: clang-13 compiler: clang++-13 - cxxstd: "11,14,17,20" + cxxstd: "14,17,20" os: ubuntu-22.04 supported: true - toolset: clang install: clang-14 compiler: clang++-14 - cxxstd: "11,14,17,20" + cxxstd: "14,17,20" os: ubuntu-22.04 supported: true - toolset: clang install: clang-15 compiler: clang++-15 - cxxstd: "11,14,17,20" + cxxstd: "14,17,20" os: ubuntu-22.04 supported: true # - toolset: clang # install: clang-16 # compiler: clang++-16 - # cxxstd: "11,14,17,20" + # cxxstd: "14,17,20" # os: ubuntu-22.04 # supported: true # macos - description: macos-11 toolset: clang - cxxstd: "11,14,17,2a" + cxxstd: "14,17,2a" os: macos-11 supported: true - description: macos-12 toolset: clang - cxxstd: "11,14,17,20" + cxxstd: "14,17,20" os: macos-11 supported: true - description: macos-13 toolset: clang - cxxstd: "11,14,17,20" + cxxstd: "14,17,20" os: macos-11 supported: true @@ -275,7 +275,7 @@ jobs: addrmd: 64 os: windows-2019 - toolset: gcc - cxxstd: "11,14,17,2a" + cxxstd: "14,17,2a" addrmd: 64 cxxflags: "cxxflags=-Wa,-mbig-obj" supported: true diff --git a/CMakeLists.txt b/CMakeLists.txt index e94a3228..0d106d7b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,6 +9,9 @@ project(boost_lockfree VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX) option(BOOST_LOCKFREE_BUILD_TESTS "Build boost::lockfree tests" ${BUILD_TESTING}) +if (NOT DEFINED CMAKE_CXX_STANDARD) + set(CMAKE_CXX_STANDARD 14) +endif() add_library(boost_lockfree INTERFACE) add_library(Boost::lockfree ALIAS boost_lockfree) @@ -33,24 +36,21 @@ if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.23) target_sources(boost_lockfree PUBLIC FILE_SET HEADERS FILES ${Headers} ) endif() +target_compile_features(boost_lockfree INTERFACE cxx_std_14) +set_target_properties( boost_lockfree PROPERTIES CMAKE_CXX_STANDARD_REQUIRED 14) + target_include_directories(boost_lockfree INTERFACE include) target_link_libraries(boost_lockfree INTERFACE Boost::align - Boost::array Boost::assert Boost::atomic Boost::config Boost::core - Boost::integer - Boost::iterator - Boost::mpl Boost::parameter Boost::predef Boost::static_assert - Boost::tuple - Boost::type_traits Boost::utility ) diff --git a/doc/lockfree.qbk b/doc/lockfree.qbk index 1b0e77d1..6bc5f948 100644 --- a/doc/lockfree.qbk +++ b/doc/lockfree.qbk @@ -270,10 +270,7 @@ problem is the blocking emulation of lock-free atomics, which in the current imp [section Supported Platforms & Compilers] -_lockfree_ has been tested on the following platforms: - -* g++ 4.4, 4.5 and 4.6, linux, x86 & x86_64 -* clang++ 3.0, linux, x86 & x86_64 +_lockfree_ requires a c++14 compliant compiler [endsect] diff --git a/include/boost/lockfree/detail/atomic.hpp b/include/boost/lockfree/detail/atomic.hpp index 24726003..cd914540 100644 --- a/include/boost/lockfree/detail/atomic.hpp +++ b/include/boost/lockfree/detail/atomic.hpp @@ -7,51 +7,7 @@ #ifndef BOOST_LOCKFREE_DETAIL_ATOMIC_HPP #define BOOST_LOCKFREE_DETAIL_ATOMIC_HPP -#include - -#ifndef BOOST_LOCKFREE_FORCE_STD_ATOMIC - -# define BOOST_LOCKFREE_NO_HDR_ATOMIC - -// MSVC supports atomic<> from version 2012 onwards. -# if defined( BOOST_MSVC ) && ( BOOST_MSVC >= 1700 ) -# undef BOOST_LOCKFREE_NO_HDR_ATOMIC -# endif - - -// GCC supports atomic<> from version 4.8 onwards. -# if ( BOOST_GCC >= 40800 ) && ( __cplusplus >= 201103L ) -# undef BOOST_LOCKFREE_NO_HDR_ATOMIC -# endif - - -// Apple clang is 2 mayor versions ahead, but in fact 1 minor version behind -# ifdef BOOST_CLANG - -# define BOOST_ATOMIC_CLANG_VERSION ( __clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__ ) - -# if defined( __apple_build_version__ ) && ( BOOST_ATOMIC_CLANG_VERSION >= 60100 ) && ( __cplusplus >= 201103L ) -# undef BOOST_LOCKFREE_NO_HDR_ATOMIC -# endif - -# if !defined( __apple_build_version__ ) && ( BOOST_ATOMIC_CLANG_VERSION >= 30600 ) && ( __cplusplus >= 201103L ) -# undef BOOST_LOCKFREE_NO_HDR_ATOMIC -# endif - -# undef BOOST_ATOMIC_CLANG_VERSION - -# endif // BOOST_CLANG - -// Stdlib should also be checked -# include -# if defined( BOOST_NO_CXX11_HDR_ATOMIC ) && !defined( BOOST_LOCKFREE_NO_HDR_ATOMIC ) -# define BOOST_LOCKFREE_NO_HDR_ATOMIC -# endif - -#endif // BOOST_LOCKFREE_FORCE_STD_ATOMIC - - -#if defined( BOOST_LOCKFREE_NO_HDR_ATOMIC ) || defined( BOOST_LOCKFREE_FORCE_BOOST_ATOMIC ) +#if defined( BOOST_LOCKFREE_FORCE_BOOST_ATOMIC ) # include #else # include @@ -60,7 +16,7 @@ namespace boost { namespace lockfree { namespace detail { -#if defined( BOOST_LOCKFREE_NO_HDR_ATOMIC ) || defined( BOOST_LOCKFREE_FORCE_BOOST_ATOMIC ) +#if defined( BOOST_LOCKFREE_FORCE_BOOST_ATOMIC ) using boost::atomic; using boost::memory_order_acquire; using boost::memory_order_consume; diff --git a/include/boost/lockfree/detail/copy_payload.hpp b/include/boost/lockfree/detail/copy_payload.hpp index 9acd086f..ff06dfdb 100644 --- a/include/boost/lockfree/detail/copy_payload.hpp +++ b/include/boost/lockfree/detail/copy_payload.hpp @@ -9,8 +9,7 @@ #ifndef BOOST_LOCKFREE_DETAIL_COPY_PAYLOAD_HPP_INCLUDED #define BOOST_LOCKFREE_DETAIL_COPY_PAYLOAD_HPP_INCLUDED -#include -#include +#include #if defined( _MSC_VER ) # pragma warning( push ) @@ -40,36 +39,11 @@ struct copy_constructible_and_copyable template < typename T, typename U > void copy_payload( T& t, U& u ) { - typedef typename boost::mpl::if_< typename boost::is_convertible< T, U >::type, - copy_convertible, - copy_constructible_and_copyable >::type copy_type; + static constexpr bool is_convertible = std::is_convertible< T, U >::value; + typedef std::conditional_t< is_convertible, copy_convertible, copy_constructible_and_copyable > copy_type; copy_type::copy( t, u ); } -template < typename T > -struct consume_via_copy -{ - consume_via_copy( T& out ) : - out_( out ) - {} - - template < typename U > - void operator()( U& element ) - { - copy_payload( element, out_ ); - } - - T& out_; -}; - -struct consume_noop -{ - template < typename U > - void operator()( const U& ) - {} -}; - - }}} // namespace boost::lockfree::detail #if defined( _MSC_VER ) diff --git a/include/boost/lockfree/detail/freelist.hpp b/include/boost/lockfree/detail/freelist.hpp index 0ce72f6d..e063c851 100644 --- a/include/boost/lockfree/detail/freelist.hpp +++ b/include/boost/lockfree/detail/freelist.hpp @@ -9,18 +9,17 @@ #ifndef BOOST_LOCKFREE_FREELIST_HPP_INCLUDED #define BOOST_LOCKFREE_FREELIST_HPP_INCLUDED +#include #include #include #include - -#include -#include -#include -#include -#include +#include #include #include +#include +#include +#include #include #include @@ -34,6 +33,8 @@ namespace boost { namespace lockfree { namespace detail { +//---------------------------------------------------------------------------------------------------------------------- + template < typename T, typename Alloc = std::allocator< T > > class freelist_stack : Alloc { @@ -261,22 +262,15 @@ class BOOST_ALIGNMENT( 4 ) // workaround for bugs in MSVC tagged_index { public: - typedef boost::uint16_t tag_t; - typedef boost::uint16_t index_t; + typedef std::uint16_t tag_t; + typedef std::uint16_t index_t; /** uninitialized constructor */ - tagged_index( void ) BOOST_NOEXCEPT //: index(0), tag(0) + tagged_index( void ) noexcept //: index(0), tag(0) {} /** copy constructor */ -#ifdef BOOST_NO_CXX11_DEFAULTED_FUNCTIONS - tagged_index( tagged_index const& rhs ) : - index( rhs.index ), - tag( rhs.tag ) - {} -#else tagged_index( tagged_index const& rhs ) = default; -#endif explicit tagged_index( index_t i, tag_t t = 0 ) : index( i ), @@ -330,13 +324,15 @@ class BOOST_ALIGNMENT( 4 ) // workaround for bugs in MSVC tag_t tag; }; +//---------------------------------------------------------------------------------------------------------------------- + template < typename T, std::size_t size > struct BOOST_ALIGNMENT( BOOST_LOCKFREE_CACHELINE_BYTES ) compiletime_sized_freelist_storage { // array-based freelists only support a 16bit address space. BOOST_STATIC_ASSERT( size < 65536 ); - boost::array< char, size * sizeof( T ) + 64 > data; + std::array< char, size * sizeof( T ) + 64 > data; // unused ... only for API purposes template < typename Allocator > @@ -357,6 +353,8 @@ struct BOOST_ALIGNMENT( BOOST_LOCKFREE_CACHELINE_BYTES ) compiletime_sized_freel } }; +//---------------------------------------------------------------------------------------------------------------------- + template < typename T, typename Alloc = std::allocator< T > > struct runtime_sized_freelist_storage : boost::alignment::aligned_allocator_adaptor< Alloc, BOOST_LOCKFREE_CACHELINE_BYTES > @@ -393,6 +391,7 @@ struct runtime_sized_freelist_storage : } }; +//---------------------------------------------------------------------------------------------------------------------- template < typename T, typename NodeStorage = runtime_sized_freelist_storage< T > > class fixed_size_freelist : NodeStorage @@ -613,26 +612,35 @@ class fixed_size_freelist : NodeStorage atomic< tagged_index > pool_; }; +//---------------------------------------------------------------------------------------------------------------------- + template < typename T, typename Alloc, bool IsCompileTimeSized, bool IsFixedSize, std::size_t Capacity > struct select_freelist { - typedef typename mpl::if_c< IsCompileTimeSized, + typedef std::conditional_t< IsCompileTimeSized, compiletime_sized_freelist_storage< T, Capacity >, - runtime_sized_freelist_storage< T, Alloc > >::type fixed_sized_storage_type; + runtime_sized_freelist_storage< T, Alloc > > + fixed_sized_storage_type; - typedef typename mpl::if_c< IsCompileTimeSized || IsFixedSize, + typedef std::conditional_t< IsCompileTimeSized || IsFixedSize, fixed_size_freelist< T, fixed_sized_storage_type >, - freelist_stack< T, Alloc > >::type type; + freelist_stack< T, Alloc > > + type; }; +template < typename T, typename Alloc, bool IsCompileTimeSized, bool IsFixedSize, std::size_t Capacity > +using select_freelist_t = typename select_freelist< T, Alloc, IsCompileTimeSized, IsFixedSize, Capacity >::type; + +//---------------------------------------------------------------------------------------------------------------------- + template < typename T, bool IsNodeBased > struct select_tagged_handle { - typedef typename mpl::if_c< IsNodeBased, tagged_ptr< T >, tagged_index >::type tagged_handle_type; - - typedef typename mpl::if_c< IsNodeBased, T*, typename tagged_index::index_t >::type handle_type; + typedef std::conditional_t< IsNodeBased, tagged_ptr< T >, tagged_index > tagged_handle_type; + typedef std::conditional_t< IsNodeBased, T*, typename tagged_index::index_t > handle_type; }; +//---------------------------------------------------------------------------------------------------------------------- }}} // namespace boost::lockfree::detail diff --git a/include/boost/lockfree/detail/parameter.hpp b/include/boost/lockfree/detail/parameter.hpp index 27364358..c88d1fd7 100644 --- a/include/boost/lockfree/detail/parameter.hpp +++ b/include/boost/lockfree/detail/parameter.hpp @@ -14,61 +14,70 @@ #include #include #include -#include - -#include +#include namespace boost { namespace lockfree { namespace detail { -namespace mpl = boost::mpl; +//---------------------------------------------------------------------------------------------------------------------- + +template < typename bound_args, typename tag_type, typename default_ > +using extract_arg_or_default_t = typename parameter::binding< bound_args, tag_type, default_ >::type; + +struct no_such_parameter_t +{}; template < typename bound_args, typename tag_type > -struct has_arg -{ - typedef typename parameter::binding< bound_args, tag_type, mpl::void_ >::type type; - static const bool value = mpl::is_not_void_< type >::type::value; -}; +using has_no_arg_t + = std::is_same< extract_arg_or_default_t< bound_args, tag_type, no_such_parameter_t >, no_such_parameter_t >; +//---------------------------------------------------------------------------------------------------------------------- template < typename bound_args > struct extract_capacity { - static const bool has_capacity = has_arg< bound_args, tag::capacity >::value; - - typedef - typename mpl::if_c< has_capacity, typename has_arg< bound_args, tag::capacity >::type, mpl::size_t< 0 > >::type - capacity_t; - - static const std::size_t capacity = capacity_t::value; + using capacity_t = extract_arg_or_default_t< bound_args, tag::capacity, std::integral_constant< size_t, 0 > >; + using has_no_capacity_t = has_no_arg_t< bound_args, tag::capacity >; + static constexpr std::size_t capacity = capacity_t::value; + static constexpr bool has_capacity = !has_no_capacity_t::value; }; +template < typename bound_args > +using extract_capacity_t = typename extract_capacity< bound_args >::type; + +//---------------------------------------------------------------------------------------------------------------------- template < typename bound_args, typename T > struct extract_allocator { - static const bool has_allocator = has_arg< bound_args, tag::allocator >::value; + using default_allocator = boost::alignment::aligned_allocator< T, BOOST_LOCKFREE_CACHELINE_BYTES >; + using allocator_t = extract_arg_or_default_t< bound_args, tag::allocator, default_allocator >; - typedef - typename mpl::if_c< has_allocator, - typename has_arg< bound_args, tag::allocator >::type, - boost::alignment::aligned_allocator< T, BOOST_LOCKFREE_CACHELINE_BYTES > >::type allocator_arg; + using has_no_allocator_t = has_no_arg_t< bound_args, tag::allocator >; + static constexpr bool has_allocator = !has_no_allocator_t::value; - typedef typename boost::allocator_rebind< allocator_arg, T >::type type; + typedef typename boost::allocator_rebind< allocator_t, T >::type type; }; +template < typename bound_args, typename T > +using extract_allocator_t = typename extract_allocator< bound_args, T >::type; + +//---------------------------------------------------------------------------------------------------------------------- + template < typename bound_args, bool default_ = false > struct extract_fixed_sized { - static const bool has_fixed_sized = has_arg< bound_args, tag::fixed_sized >::value; + using capacity_t + = extract_arg_or_default_t< bound_args, tag::fixed_sized, std::integral_constant< bool, default_ > >; - typedef typename mpl::if_c< has_fixed_sized, - typename has_arg< bound_args, tag::fixed_sized >::type, - mpl::bool_< default_ > >::type type; - - static const bool value = type::value; + static constexpr bool value = capacity_t::value; }; +template < typename bound_args, bool default_ = false > +using extract_fixed_sized_t = typename extract_fixed_sized< bound_args, default_ >::type; + +//---------------------------------------------------------------------------------------------------------------------- + }}} // namespace boost::lockfree::detail diff --git a/include/boost/lockfree/detail/tagged_ptr_dcas.hpp b/include/boost/lockfree/detail/tagged_ptr_dcas.hpp index 237866e5..4a772e35 100644 --- a/include/boost/lockfree/detail/tagged_ptr_dcas.hpp +++ b/include/boost/lockfree/detail/tagged_ptr_dcas.hpp @@ -12,6 +12,7 @@ #include /* for std::size_t */ #include +#include #include namespace boost { namespace lockfree { namespace detail { @@ -32,17 +33,10 @@ class typedef std::size_t tag_t; /** uninitialized constructor */ - tagged_ptr( void ) BOOST_NOEXCEPT //: ptr(0), tag(0) + tagged_ptr( void ) noexcept //: ptr(0), tag(0) {} -#ifdef BOOST_NO_CXX11_DEFAULTED_FUNCTIONS - tagged_ptr( tagged_ptr const& p ) : - ptr( p.ptr ), - tag( p.tag ) - {} -#else tagged_ptr( tagged_ptr const& p ) = default; -#endif explicit tagged_ptr( T* p, tag_t t = 0 ) : ptr( p ), @@ -51,15 +45,7 @@ class /** unsafe set operation */ /* @{ */ -#ifdef BOOST_NO_CXX11_DEFAULTED_FUNCTIONS - tagged_ptr& operator=( tagged_ptr const& p ) - { - set( p.ptr, p.tag ); - return *this; - } -#else tagged_ptr& operator=( tagged_ptr const& p ) = default; -#endif void set( T* p, tag_t t ) { diff --git a/include/boost/lockfree/detail/tagged_ptr_ptrcompression.hpp b/include/boost/lockfree/detail/tagged_ptr_ptrcompression.hpp index c2cf6ff3..6df04d89 100644 --- a/include/boost/lockfree/detail/tagged_ptr_ptrcompression.hpp +++ b/include/boost/lockfree/detail/tagged_ptr_ptrcompression.hpp @@ -9,11 +9,10 @@ #ifndef BOOST_LOCKFREE_TAGGED_PTR_PTRCOMPRESSION_HPP_INCLUDED #define BOOST_LOCKFREE_TAGGED_PTR_PTRCOMPRESSION_HPP_INCLUDED -#include /* for std::size_t */ +#include #include -#include -#include +#include namespace boost { namespace lockfree { namespace detail { @@ -22,10 +21,10 @@ namespace boost { namespace lockfree { namespace detail { template < class T > class tagged_ptr { - typedef boost::uint64_t compressed_ptr_t; + typedef std::uint64_t compressed_ptr_t; public: - typedef boost::uint16_t tag_t; + typedef std::uint16_t tag_t; private: union cast_unit @@ -34,8 +33,8 @@ class tagged_ptr tag_t tag[ 4 ]; }; - static const int tag_index = 3; - static const compressed_ptr_t ptr_mask = 0xffffffffffffUL; //(1L<<48L)-1; + static constexpr int tag_index = 3; + static constexpr compressed_ptr_t ptr_mask = 0xffffffffffffUL; //(1L<<48L)-1; static T* extract_ptr( volatile compressed_ptr_t const& i ) { @@ -59,17 +58,11 @@ class tagged_ptr public: /** uninitialized constructor */ - tagged_ptr( void ) BOOST_NOEXCEPT //: ptr(0), tag(0) + tagged_ptr( void ) noexcept //: ptr(0), tag(0) {} /** copy constructor */ -# ifdef BOOST_NO_CXX11_DEFAULTED_FUNCTIONS - tagged_ptr( tagged_ptr const& p ) : - ptr( p.ptr ) - {} -# else tagged_ptr( tagged_ptr const& p ) = default; -# endif explicit tagged_ptr( T* p, tag_t t = 0 ) : ptr( pack_ptr( p, t ) ) @@ -77,15 +70,7 @@ class tagged_ptr /** unsafe set operation */ /* @{ */ -# ifdef BOOST_NO_CXX11_DEFAULTED_FUNCTIONS - tagged_ptr& operator=( tagged_ptr const& p ) - { - ptr = p.ptr; - return *this; - } -# else tagged_ptr& operator=( tagged_ptr const& p ) = default; -# endif void set( T* p, tag_t t ) { diff --git a/include/boost/lockfree/lockfree_forward.hpp b/include/boost/lockfree/lockfree_forward.hpp index 81d5f9ce..ec7c8e84 100644 --- a/include/boost/lockfree/lockfree_forward.hpp +++ b/include/boost/lockfree/lockfree_forward.hpp @@ -15,10 +15,6 @@ # include -# ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES -# include -# endif - namespace boost { namespace lockfree { // policies @@ -34,25 +30,13 @@ struct allocator; // data structures -# ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES -template < typename T, class A0 = boost::parameter::void_, class A1 = boost::parameter::void_, class A2 = boost::parameter::void_ > -# else template < typename T, typename... Options > -# endif class queue; -# ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES -template < typename T, class A0 = boost::parameter::void_, class A1 = boost::parameter::void_, class A2 = boost::parameter::void_ > -# else template < typename T, typename... Options > -# endif class stack; -# ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES -template < typename T, class A0 = boost::parameter::void_, class A1 = boost::parameter::void_ > -# else template < typename T, typename... Options > -# endif class spsc_queue; }} // namespace boost::lockfree diff --git a/include/boost/lockfree/policies.hpp b/include/boost/lockfree/policies.hpp index e1acc6fc..d2405043 100644 --- a/include/boost/lockfree/policies.hpp +++ b/include/boost/lockfree/policies.hpp @@ -9,10 +9,10 @@ #ifndef BOOST_LOCKFREE_POLICIES_HPP_INCLUDED #define BOOST_LOCKFREE_POLICIES_HPP_INCLUDED -#include -#include #include +#include + namespace boost { namespace lockfree { #ifndef BOOST_DOXYGEN_INVOKED @@ -36,7 +36,7 @@ struct capacity; * This implies that a data structure is bounded. * */ template < bool IsFixedSized > -struct fixed_sized : boost::parameter::template_keyword< tag::fixed_sized, boost::mpl::bool_< IsFixedSized > > +struct fixed_sized : boost::parameter::template_keyword< tag::fixed_sized, std::integral_constant< bool, IsFixedSized > > {}; /** Sets the \b capacity of a data structure at compile-time. @@ -44,7 +44,7 @@ struct fixed_sized : boost::parameter::template_keyword< tag::fixed_sized, boost * This implies that a data structure is bounded and fixed-sized. * */ template < size_t Size > -struct capacity : boost::parameter::template_keyword< tag::capacity, boost::mpl::size_t< Size > > +struct capacity : boost::parameter::template_keyword< tag::capacity, std::integral_constant< size_t, Size > > {}; /** Defines the \b allocator type of a data structure. diff --git a/include/boost/lockfree/queue.hpp b/include/boost/lockfree/queue.hpp index 19c950df..3ef2e141 100644 --- a/include/boost/lockfree/queue.hpp +++ b/include/boost/lockfree/queue.hpp @@ -14,16 +14,15 @@ #include #include // for BOOST_LIKELY & BOOST_ALIGNMENT #include +#include +#include #include -#include -#include #include #include #include #include #include - #include #ifdef BOOST_HAS_PRAGMA_ONCE @@ -78,35 +77,23 @@ typedef parameter::parameters< boost::parameter::optional< tag::allocator >, boo * - T must have a trivial destructor * * */ -#ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES -template < typename T, class A0, class A1, class A2 > -#else template < typename T, typename... Options > -#endif class queue { private: #ifndef BOOST_DOXYGEN_INVOKED -# ifdef BOOST_HAS_TRIVIAL_DESTRUCTOR - BOOST_STATIC_ASSERT( ( boost::has_trivial_destructor< T >::value ) ); -# endif + BOOST_STATIC_ASSERT( ( std::is_trivially_destructible< T >::value ) ); + BOOST_STATIC_ASSERT( ( std::is_trivially_assignable< T&, T >::value ) ); -# ifdef BOOST_HAS_TRIVIAL_ASSIGN - BOOST_STATIC_ASSERT( ( boost::has_trivial_assign< T >::value ) ); -# endif - -# ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES - typedef typename detail::queue_signature::bind< A0, A1, A2 >::type bound_args; -# else typedef typename detail::queue_signature::bind< Options... >::type bound_args; -# endif - static const bool has_capacity = detail::extract_capacity< bound_args >::has_capacity; - static const size_t capacity = detail::extract_capacity< bound_args >::capacity + 1; // the queue uses one dummy node - static const bool fixed_sized = detail::extract_fixed_sized< bound_args >::value; - static const bool node_based = !( has_capacity || fixed_sized ); - static const bool compile_time_sized = has_capacity; + static constexpr bool has_capacity = detail::extract_capacity< bound_args >::has_capacity; + static constexpr size_t capacity + = detail::extract_capacity< bound_args >::capacity + 1; // the queue uses one dummy node + static constexpr bool fixed_sized = detail::extract_fixed_sized< bound_args >::value; + static constexpr bool node_based = !( has_capacity || fixed_sized ); + static constexpr bool compile_time_sized = has_capacity; struct BOOST_ALIGNMENT( BOOST_LOCKFREE_CACHELINE_BYTES ) node { @@ -133,9 +120,8 @@ class queue T data; }; - typedef typename detail::extract_allocator< bound_args, node >::type node_allocator; - typedef - typename detail::select_freelist< node, node_allocator, compile_time_sized, fixed_sized, capacity >::type pool_t; + typedef detail::extract_allocator_t< bound_args, node > node_allocator; + typedef detail::select_freelist_t< node, node_allocator, compile_time_sized, fixed_sized, capacity > pool_t; typedef typename pool_t::tagged_node_handle tagged_node_handle; typedef typename detail::select_tagged_handle< node, node_based >::handle_type handle_type; @@ -155,9 +141,6 @@ class queue #endif - BOOST_DELETED_FUNCTION( queue( queue const& ) ) - BOOST_DELETED_FUNCTION( queue& operator=( queue const& ) ) - public: typedef T value_type; typedef typename implementation_defined::allocator allocator; @@ -195,13 +178,12 @@ class queue * * \pre Must specify a capacity<> argument * */ - template < typename U > + template < typename U, typename Enabler = std::enable_if< has_capacity > > explicit queue( typename boost::allocator_rebind< node_allocator, U >::type const& alloc ) : head_( tagged_node_handle( 0, 0 ) ), tail_( tagged_node_handle( 0, 0 ) ), pool( alloc, capacity ) { - BOOST_STATIC_ASSERT( has_capacity ); initialize(); } @@ -209,14 +191,12 @@ class queue * * \pre Must specify a capacity<> argument * */ + template < typename Enabler = std::enable_if< has_capacity > > explicit queue( allocator const& alloc ) : head_( tagged_node_handle( 0, 0 ) ), tail_( tagged_node_handle( 0, 0 ) ), pool( alloc, capacity ) { - // Don't use BOOST_STATIC_ASSERT() here since it will be evaluated when compiling - // this function and this function may be compiled even when it isn't being used. - BOOST_ASSERT( has_capacity ); initialize(); } @@ -226,14 +206,12 @@ class queue * * \pre Must \b not specify a capacity<> argument * */ + template < typename Enabler = std::enable_if< !has_capacity > > explicit queue( size_type n ) : head_( tagged_node_handle( 0, 0 ) ), tail_( tagged_node_handle( 0, 0 ) ), pool( node_allocator(), n + 1 ) { - // Don't use BOOST_STATIC_ASSERT() here since it will be evaluated when compiling - // this function and this function may be compiled even when it isn't being used. - BOOST_ASSERT( !has_capacity ); initialize(); } @@ -243,13 +221,12 @@ class queue * * \pre Must \b not specify a capacity<> argument * */ - template < typename U > + template < typename U, typename Enabler = std::enable_if< !has_capacity > > queue( size_type n, typename boost::allocator_rebind< node_allocator, U >::type const& alloc ) : head_( tagged_node_handle( 0, 0 ) ), tail_( tagged_node_handle( 0, 0 ) ), pool( alloc, n + 1 ) { - BOOST_STATIC_ASSERT( !has_capacity ); initialize(); } @@ -259,15 +236,20 @@ class queue * * \pre Must \b not specify a capacity<> argument * */ + template < typename Enabler = std::enable_if< !has_capacity > > queue( size_type n, allocator const& alloc ) : head_( tagged_node_handle( 0, 0 ) ), tail_( tagged_node_handle( 0, 0 ) ), pool( alloc, n + 1 ) { - BOOST_STATIC_ASSERT( !has_capacity ); initialize(); } + queue( const queue& ) = delete; + queue& operator=( const queue& ) = delete; + queue( queue&& ) = delete; + queue& operator=( queue&& ) = delete; + /** \copydoc boost::lockfree::stack::reserve * */ void reserve( size_type n ) @@ -286,8 +268,7 @@ class queue * */ ~queue( void ) { - T dummy; - while ( unsynchronized_pop( dummy ) ) {} + consume_all( []( const T& ) {} ); pool.template destruct< false >( head_.load( memory_order_relaxed ) ); } @@ -520,19 +501,7 @@ class queue * \note Thread-safe and non-blocking, if functor is thread-safe and non-blocking * */ template < typename Functor > - bool consume_one( Functor& f ) - { - T element; - bool success = pop( element ); - if ( success ) - f( element ); - - return success; - } - - /// \copydoc boost::lockfree::queue::consume_one(Functor & rhs) - template < typename Functor > - bool consume_one( Functor const& f ) + bool consume_one( Functor&& f ) { T element; bool success = pop( element ); @@ -551,18 +520,7 @@ class queue * \note Thread-safe and non-blocking, if functor is thread-safe and non-blocking * */ template < typename Functor > - size_t consume_all( Functor& f ) - { - size_t element_count = 0; - while ( consume_one( f ) ) - element_count += 1; - - return element_count; - } - - /// \copydoc boost::lockfree::queue::consume_all(Functor & rhs) - template < typename Functor > - size_t consume_all( Functor const& f ) + size_t consume_all( Functor&& f ) { size_t element_count = 0; while ( consume_one( f ) ) @@ -574,7 +532,7 @@ class queue private: #ifndef BOOST_DOXYGEN_INVOKED atomic< tagged_node_handle > head_; - static const int padding_size = BOOST_LOCKFREE_CACHELINE_BYTES - sizeof( tagged_node_handle ); + static constexpr int padding_size = BOOST_LOCKFREE_CACHELINE_BYTES - sizeof( tagged_node_handle ); char padding1[ padding_size ]; atomic< tagged_node_handle > tail_; char padding2[ padding_size ]; diff --git a/include/boost/lockfree/spsc_queue.hpp b/include/boost/lockfree/spsc_queue.hpp index 30a1e00b..3596165a 100644 --- a/include/boost/lockfree/spsc_queue.hpp +++ b/include/boost/lockfree/spsc_queue.hpp @@ -12,24 +12,21 @@ #include #include +#include #include #include #include // for BOOST_LIKELY #include -#include +#include +#include +#include #include -#include -#include - -#include -#include #include #include #include #include - #include #ifdef BOOST_HAS_PRAGMA_ONCE @@ -39,22 +36,16 @@ namespace boost { namespace lockfree { namespace detail { -typedef parameter::parameters< boost::parameter::optional< tag::capacity >, boost::parameter::optional< tag::allocator > > - ringbuffer_signature; - template < typename T > class ringbuffer_base { #ifndef BOOST_DOXYGEN_INVOKED protected: - typedef std::size_t size_t; - static const int padding_size = BOOST_LOCKFREE_CACHELINE_BYTES - sizeof( size_t ); - atomic< size_t > write_index_; - char padding1[ padding_size ]; /* force read_index and write_index to different cache lines */ - atomic< size_t > read_index_; - - BOOST_DELETED_FUNCTION( ringbuffer_base( ringbuffer_base const& ) ) - BOOST_DELETED_FUNCTION( ringbuffer_base& operator=( ringbuffer_base const& ) ) + typedef std::size_t size_t; + static constexpr int padding_size = BOOST_LOCKFREE_CACHELINE_BYTES - sizeof( size_t ); + atomic< size_t > write_index_; + char padding1[ padding_size ]; /* force read_index and write_index to different cache lines */ + atomic< size_t > read_index_; protected: ringbuffer_base( void ) : @@ -138,12 +129,12 @@ class ringbuffer_base size_t new_write_index = write_index + input_count; - const ConstIterator last = boost::next( begin, input_count ); + const ConstIterator last = std::next( begin, input_count ); if ( write_index + input_count > max_size ) { /* copy data in two sections */ const size_t count0 = max_size - write_index; - const ConstIterator midpoint = boost::next( begin, count0 ); + const ConstIterator midpoint = std::next( begin, count0 ); std::uninitialized_copy( begin, midpoint, internal_buffer + write_index ); std::uninitialized_copy( midpoint, last, internal_buffer ); @@ -160,7 +151,7 @@ class ringbuffer_base } template < typename Functor > - bool consume_one( Functor& functor, T* buffer, size_t max_size ) + bool consume_one( Functor&& functor, T* buffer, size_t max_size ) { const size_t write_index = write_index_.load( memory_order_acquire ); const size_t read_index = read_index_.load( memory_order_relaxed ); // only written from pop thread @@ -177,59 +168,7 @@ class ringbuffer_base } template < typename Functor > - bool consume_one( Functor const& functor, T* buffer, size_t max_size ) - { - const size_t write_index = write_index_.load( memory_order_acquire ); - const size_t read_index = read_index_.load( memory_order_relaxed ); // only written from pop thread - if ( empty( write_index, read_index ) ) - return false; - - T& object_to_consume = buffer[ read_index ]; - functor( object_to_consume ); - object_to_consume.~T(); - - size_t next = next_index( read_index, max_size ); - read_index_.store( next, memory_order_release ); - return true; - } - - template < typename Functor > - size_t consume_all( Functor const& functor, T* internal_buffer, size_t max_size ) - { - const size_t write_index = write_index_.load( memory_order_acquire ); - const size_t read_index = read_index_.load( memory_order_relaxed ); // only written from pop thread - - const size_t avail = read_available( write_index, read_index, max_size ); - - if ( avail == 0 ) - return 0; - - const size_t output_count = avail; - - size_t new_read_index = read_index + output_count; - - if ( read_index + output_count > max_size ) { - /* copy data in two sections */ - const size_t count0 = max_size - read_index; - const size_t count1 = output_count - count0; - - run_functor_and_delete( internal_buffer + read_index, internal_buffer + max_size, functor ); - run_functor_and_delete( internal_buffer, internal_buffer + count1, functor ); - - new_read_index -= max_size; - } else { - run_functor_and_delete( internal_buffer + read_index, internal_buffer + read_index + output_count, functor ); - - if ( new_read_index == max_size ) - new_read_index = 0; - } - - read_index_.store( new_read_index, memory_order_release ); - return output_count; - } - - template < typename Functor > - size_t consume_all( Functor& functor, T* internal_buffer, size_t max_size ) + size_t consume_all( Functor&& functor, T* internal_buffer, size_t max_size ) { const size_t write_index = write_index_.load( memory_order_acquire ); const size_t read_index = read_index_.load( memory_order_relaxed ); // only written from pop thread @@ -348,11 +287,9 @@ class ringbuffer_base * */ void reset( void ) { - if ( !boost::has_trivial_destructor< T >::value ) { + if ( !std::is_trivially_destructible< T >::value ) { // make sure to call all destructors! - - detail::consume_noop consume_functor; - (void)consume_all( consume_functor ); + consume_all( []( const T& ) {} ); } else { write_index_.store( 0, memory_order_relaxed ); read_index_.store( 0, memory_order_release ); @@ -387,7 +324,7 @@ class ringbuffer_base template < class OutputIterator > OutputIterator copy_and_delete( T* first, T* last, OutputIterator out ) { - if ( boost::has_trivial_destructor< T >::value ) { + if ( std::is_trivially_destructible< T >::value ) { return std::copy( first, last, out ); // will use memcpy if possible } else { for ( ; first != last; ++first, ++out ) { @@ -399,16 +336,7 @@ class ringbuffer_base } template < class Functor > - void run_functor_and_delete( T* first, T* last, Functor& functor ) - { - for ( ; first != last; ++first ) { - functor( *first ); - first->~T(); - } - } - - template < class Functor > - void run_functor_and_delete( T* first, T* last, Functor const& functor ) + void run_functor_and_delete( T* first, T* last, Functor&& functor ) { for ( ; first != last; ++first ) { functor( *first ); @@ -420,8 +348,8 @@ class ringbuffer_base template < typename T, std::size_t MaxSize > class compile_time_sized_ringbuffer : public ringbuffer_base< T > { - typedef std::size_t size_type; - static const std::size_t max_size = MaxSize + 1; + typedef std::size_t size_type; + static constexpr std::size_t max_size = MaxSize + 1; typedef typename boost::aligned_storage< max_size * sizeof( T ), boost::alignment_of< T >::value >::type storage_type; @@ -447,8 +375,7 @@ class compile_time_sized_ringbuffer : public ringbuffer_base< T > ~compile_time_sized_ringbuffer( void ) { // destroy all remaining items - detail::consume_noop consume_functor; - (void)consume_all( consume_functor ); + consume_all( []( const T& ) {} ); } public: @@ -458,25 +385,13 @@ class compile_time_sized_ringbuffer : public ringbuffer_base< T > } template < typename Functor > - bool consume_one( Functor& f ) + bool consume_one( Functor&& f ) { return ringbuffer_base< T >::consume_one( f, data(), max_size ); } template < typename Functor > - bool consume_one( Functor const& f ) - { - return ringbuffer_base< T >::consume_one( f, data(), max_size ); - } - - template < typename Functor > - size_type consume_all( Functor& f ) - { - return ringbuffer_base< T >::consume_all( f, data(), max_size ); - } - - template < typename Functor > - size_type consume_all( Functor const& f ) + size_type consume_all( Functor&& f ) { return ringbuffer_base< T >::consume_all( f, data(), max_size ); } @@ -523,15 +438,11 @@ class compile_time_sized_ringbuffer : public ringbuffer_base< T > template < typename T, typename Alloc > class runtime_sized_ringbuffer : public ringbuffer_base< T >, private Alloc { - typedef std::size_t size_type; - size_type max_elements_; -#ifdef BOOST_NO_CXX11_ALLOCATOR - typedef typename Alloc::pointer pointer; -#else + typedef std::size_t size_type; + size_type max_elements_; typedef std::allocator_traits< Alloc > allocator_traits; typedef typename allocator_traits::pointer pointer; -#endif - pointer array_; + pointer array_; protected: size_type max_number_of_elements() const @@ -543,12 +454,8 @@ class runtime_sized_ringbuffer : public ringbuffer_base< T >, private Alloc explicit runtime_sized_ringbuffer( size_type max_elements ) : max_elements_( max_elements + 1 ) { -#ifdef BOOST_NO_CXX11_ALLOCATOR - array_ = Alloc::allocate( max_elements_ ); -#else Alloc& alloc = *this; array_ = allocator_traits::allocate( alloc, max_elements_ ); -#endif } template < typename U > @@ -556,38 +463,25 @@ class runtime_sized_ringbuffer : public ringbuffer_base< T >, private Alloc Alloc( alloc ), max_elements_( max_elements + 1 ) { -#ifdef BOOST_NO_CXX11_ALLOCATOR - array_ = Alloc::allocate( max_elements_ ); -#else Alloc& allocator = *this; array_ = allocator_traits::allocate( allocator, max_elements_ ); -#endif } runtime_sized_ringbuffer( Alloc const& alloc, size_type max_elements ) : Alloc( alloc ), max_elements_( max_elements + 1 ) { -#ifdef BOOST_NO_CXX11_ALLOCATOR - array_ = Alloc::allocate( max_elements_ ); -#else Alloc& allocator = *this; array_ = allocator_traits::allocate( allocator, max_elements_ ); -#endif } ~runtime_sized_ringbuffer( void ) { // destroy all remaining items - detail::consume_noop consume_functor; - (void)consume_all( consume_functor ); + consume_all( []( const T& ) {} ); -#ifdef BOOST_NO_CXX11_ALLOCATOR - Alloc::deallocate( array_, max_elements_ ); -#else Alloc& allocator = *this; allocator_traits::deallocate( allocator, array_, max_elements_ ); -#endif } bool push( T const& t ) @@ -596,25 +490,13 @@ class runtime_sized_ringbuffer : public ringbuffer_base< T >, private Alloc } template < typename Functor > - bool consume_one( Functor& f ) - { - return ringbuffer_base< T >::consume_one( f, &*array_, max_elements_ ); - } - - template < typename Functor > - bool consume_one( Functor const& f ) + bool consume_one( Functor&& f ) { return ringbuffer_base< T >::consume_one( f, &*array_, max_elements_ ); } template < typename Functor > - size_type consume_all( Functor& f ) - { - return ringbuffer_base< T >::consume_all( f, &*array_, max_elements_ ); - } - - template < typename Functor > - size_type consume_all( Functor const& f ) + size_type consume_all( Functor&& f ) { return ringbuffer_base< T >::consume_all( f, &*array_, max_elements_ ); } @@ -658,35 +540,30 @@ class runtime_sized_ringbuffer : public ringbuffer_base< T >, private Alloc } }; -#ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES -template < typename T, typename A0, typename A1 > -#else +typedef parameter::parameters< boost::parameter::optional< tag::capacity >, boost::parameter::optional< tag::allocator > > + ringbuffer_signature; + template < typename T, typename... Options > -#endif struct make_ringbuffer { -#ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES - typedef typename ringbuffer_signature::bind< A0, A1 >::type bound_args; -#else typedef typename ringbuffer_signature::bind< Options... >::type bound_args; -#endif typedef extract_capacity< bound_args > extract_capacity_t; - static const bool runtime_sized = !extract_capacity_t::has_capacity; - static const size_t capacity = extract_capacity_t::capacity; + static constexpr bool runtime_sized = !extract_capacity_t::has_capacity; + static constexpr size_t capacity = extract_capacity_t::capacity; typedef extract_allocator< bound_args, T > extract_allocator_t; + static constexpr bool has_allocator = extract_allocator_t::has_allocator; typedef typename extract_allocator_t::type allocator; - // allocator argument is only sane, for run-time sized ringbuffers - BOOST_STATIC_ASSERT( ( mpl::if_< mpl::bool_< !runtime_sized >, - mpl::bool_< !extract_allocator_t::has_allocator >, - mpl::true_ >::type::value ) ); + static constexpr bool signature_is_valid = runtime_sized ? true : !has_allocator; + BOOST_STATIC_ASSERT( signature_is_valid ); - typedef typename mpl::if_c< runtime_sized, + typedef std::conditional_t< runtime_sized, runtime_sized_ringbuffer< T, allocator >, - compile_time_sized_ringbuffer< T, capacity > >::type ringbuffer_type; + compile_time_sized_ringbuffer< T, capacity > > + ringbuffer_type; }; @@ -707,31 +584,14 @@ struct make_ringbuffer * - T must have a default constructor * - T must be copyable * */ -#ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES -template < typename T, class A0, class A1 > -#else template < typename T, typename... Options > -#endif -class spsc_queue : -#ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES - public detail::make_ringbuffer< T, A0, A1 >::ringbuffer_type -#else - public detail::make_ringbuffer< T, Options... >::ringbuffer_type -#endif +class spsc_queue : public detail::make_ringbuffer< T, Options... >::ringbuffer_type { private: #ifndef BOOST_DOXYGEN_INVOKED - -# ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES - typedef typename detail::make_ringbuffer< T, A0, A1 >::ringbuffer_type base_type; - static const bool runtime_sized = detail::make_ringbuffer< T, A0, A1 >::runtime_sized; - typedef typename detail::make_ringbuffer< T, A0, A1 >::allocator allocator_arg; -# else typedef typename detail::make_ringbuffer< T, Options... >::ringbuffer_type base_type; - static const bool runtime_sized = detail::make_ringbuffer< T, Options... >::runtime_sized; + static constexpr bool runtime_sized = detail::make_ringbuffer< T, Options... >::runtime_sized; typedef typename detail::make_ringbuffer< T, Options... >::allocator allocator_arg; -# endif - struct implementation_defined { @@ -762,11 +622,9 @@ class spsc_queue : * * \note This is just for API compatibility: an allocator isn't actually needed */ - template < typename U > + template < typename U, typename Enabler = std::enable_if< !runtime_sized > > explicit spsc_queue( typename boost::allocator_rebind< allocator, U >::type const& ) - { - BOOST_STATIC_ASSERT( !runtime_sized ); - } + {} /** Constructs a spsc_queue with a custom allocator * @@ -774,47 +632,41 @@ class spsc_queue : * * \note This is just for API compatibility: an allocator isn't actually needed */ + template < typename Enabler = std::enable_if< !runtime_sized > > explicit spsc_queue( allocator const& ) - { - // Don't use BOOST_STATIC_ASSERT() here since it will be evaluated when compiling - // this function and this function may be compiled even when it isn't being used. - BOOST_ASSERT( !runtime_sized ); - } + {} /** Constructs a spsc_queue for element_count elements * * \pre spsc_queue must be configured to be sized at run-time */ + template < typename Enabler = std::enable_if< runtime_sized > > explicit spsc_queue( size_type element_count ) : base_type( element_count ) - { - // Don't use BOOST_STATIC_ASSERT() here since it will be evaluated when compiling - // this function and this function may be compiled even when it isn't being used. - BOOST_ASSERT( runtime_sized ); - } + {} /** Constructs a spsc_queue for element_count elements with a custom allocator * * \pre spsc_queue must be configured to be sized at run-time */ - template < typename U > + template < typename U, typename Enabler = std::enable_if< runtime_sized > > spsc_queue( size_type element_count, typename boost::allocator_rebind< allocator, U >::type const& alloc ) : base_type( alloc, element_count ) - { - BOOST_STATIC_ASSERT( runtime_sized ); - } + {} /** Constructs a spsc_queue for element_count elements with a custom allocator * * \pre spsc_queue must be configured to be sized at run-time */ + template < typename Enabler = std::enable_if< runtime_sized > > spsc_queue( size_type element_count, allocator_arg const& alloc ) : base_type( alloc, element_count ) - { - // Don't use BOOST_STATIC_ASSERT() here since it will be evaluated when compiling - // this function and this function may be compiled even when it isn't being used. - BOOST_ASSERT( runtime_sized ); - } + {} + + spsc_queue( const spsc_queue& ) = delete; + spsc_queue& operator=( const spsc_queue& ) = delete; + spsc_queue( spsc_queue&& ) = delete; + spsc_queue& operator=( spsc_queue&& ) = delete; /** Pushes object t to the ringbuffer. * @@ -839,8 +691,7 @@ class spsc_queue : */ bool pop() { - detail::consume_noop consume_functor; - return consume_one( consume_functor ); + return consume_one( []( const T& ) {} ); } /** Pops one object from ringbuffer. @@ -851,11 +702,12 @@ class spsc_queue : * * \note Thread-safe and wait-free */ - template < typename U > - typename boost::enable_if< typename is_convertible< T, U >::type, bool >::type pop( U& ret ) + template < typename U, typename Enabler = std::enable_if< std::is_convertible< T, U >::value > > + bool pop( U& ret ) { - detail::consume_via_copy< U > consume_functor( ret ); - return consume_one( consume_functor ); + return consume_one( [ & ]( const T& t ) { + ret = std::move( t ); + } ); } /** Pushes as many objects from the array t as there is space. @@ -883,6 +735,19 @@ class spsc_queue : return push( t, size ); } + /** Pushes as many objects from the span t as there is space available. + * + * \pre only one thread is allowed to push data to the spsc_queue + * \return number of pushed items + * + * \note Thread-safe and wait-free + */ + template < std::size_t Extent > + size_type push( boost::span< const T, Extent > t ) + { + return push( t.data(), t.size() ); + } + /** Pushes as many objects from the range [begin, end) as there is space . * * \pre only one thread is allowed to push data to the spsc_queue @@ -929,8 +794,7 @@ class spsc_queue : * \note Thread-safe and wait-free * */ template < typename OutputIterator > - typename boost::disable_if< typename is_convertible< T, OutputIterator >::type, size_type >::type - pop( OutputIterator it ) + typename std::enable_if< !std::is_convertible< T, OutputIterator >::value, size_type >::type pop( OutputIterator it ) { return base_type::pop_to_output_iterator( it ); } @@ -944,14 +808,7 @@ class spsc_queue : * \note Thread-safe and non-blocking, if functor is thread-safe and non-blocking * */ template < typename Functor > - bool consume_one( Functor& f ) - { - return base_type::consume_one( f ); - } - - /// \copydoc boost::lockfree::spsc_queue::consume_one(Functor & rhs) - template < typename Functor > - bool consume_one( Functor const& f ) + bool consume_one( Functor&& f ) { return base_type::consume_one( f ); } @@ -965,14 +822,7 @@ class spsc_queue : * \note Thread-safe and non-blocking, if functor is thread-safe and non-blocking * */ template < typename Functor > - size_type consume_all( Functor& f ) - { - return base_type::consume_all( f ); - } - - /// \copydoc boost::lockfree::spsc_queue::consume_all(Functor & rhs) - template < typename Functor > - size_type consume_all( Functor const& f ) + size_type consume_all( Functor&& f ) { return base_type::consume_all( f ); } @@ -1028,11 +878,9 @@ class spsc_queue : * */ void reset( void ) { - if ( !boost::has_trivial_destructor< T >::value ) { + if ( !std::is_trivially_destructible< T >::value ) { // make sure to call all destructors! - - detail::consume_noop consume_functor; - (void)consume_all( consume_functor ); + consume_all( []( const T& ) {} ); } else { base_type::write_index_.store( 0, memory_order_relaxed ); base_type::read_index_.store( 0, memory_order_release ); diff --git a/include/boost/lockfree/stack.hpp b/include/boost/lockfree/stack.hpp index f7300207..6b1d831c 100644 --- a/include/boost/lockfree/stack.hpp +++ b/include/boost/lockfree/stack.hpp @@ -8,22 +8,23 @@ #define BOOST_LOCKFREE_STACK_HPP_INCLUDED #include -#include #include #include -#include +#include +#include +#include #include -#include -#include #include #include #include #include #include - #include +#include +#include + #ifdef BOOST_HAS_PRAGMA_ONCE # pragma once #endif @@ -59,22 +60,14 @@ typedef parameter::parameters< boost::parameter::optional< tag::allocator >, boo * \b Requirements: * - T must have a copy constructor * */ -#ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES -template < typename T, class A0, class A1, class A2 > -#else template < typename T, typename... Options > -#endif class stack { private: #ifndef BOOST_DOXYGEN_INVOKED - BOOST_STATIC_ASSERT( boost::is_copy_constructible< T >::value ); + BOOST_STATIC_ASSERT( std::is_copy_constructible< T >::value ); -# ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES - typedef typename detail::stack_signature::bind< A0, A1, A2 >::type bound_args; -# else typedef typename detail::stack_signature::bind< Options... >::type bound_args; -# endif static const bool has_capacity = detail::extract_capacity< bound_args >::has_capacity; static const size_t capacity = detail::extract_capacity< bound_args >::capacity; @@ -99,21 +92,17 @@ class stack typedef typename pool_t::tagged_node_handle tagged_node_handle; // check compile-time capacity - BOOST_STATIC_ASSERT( ( mpl::if_c< has_capacity, - mpl::bool_< capacity - 1 < boost::integer_traits< boost::uint16_t >::const_max >, - mpl::true_ >::type::value ) ); + static constexpr bool capacity_is_valid = has_capacity ? capacity - 1 < std::numeric_limits< std::uint16_t >::max() + : true; + BOOST_STATIC_ASSERT( capacity_is_valid ); struct implementation_defined { typedef node_allocator allocator; typedef std::size_t size_type; }; - #endif - BOOST_DELETED_FUNCTION( stack( stack const& ) ) - BOOST_DELETED_FUNCTION( stack& operator=( stack const& ) ) - public: typedef T value_type; typedef typename implementation_defined::allocator allocator; @@ -137,7 +126,7 @@ class stack * * \pre Must specify a capacity<> argument * */ - stack( void ) : + explicit stack( void ) : pool( node_allocator(), capacity ) { // Don't use BOOST_STATIC_ASSERT() here since it will be evaluated when compiling @@ -150,11 +139,10 @@ class stack * * \pre Must specify a capacity<> argument * */ - template < typename U > + template < typename U, typename Enabler = std::enable_if< has_capacity > > explicit stack( typename boost::allocator_rebind< node_allocator, U >::type const& alloc ) : pool( alloc, capacity ) { - BOOST_STATIC_ASSERT( has_capacity ); initialize(); } @@ -162,12 +150,10 @@ class stack * * \pre Must specify a capacity<> argument * */ + template < typename Enabler = std::enable_if< has_capacity > > explicit stack( allocator const& alloc ) : pool( alloc, capacity ) { - // Don't use BOOST_STATIC_ASSERT() here since it will be evaluated when compiling - // this function and this function may be compiled even when it isn't being used. - BOOST_ASSERT( has_capacity ); initialize(); } @@ -177,26 +163,29 @@ class stack * * \pre Must \b not specify a capacity<> argument * */ + template < typename Enabler = std::enable_if< !has_capacity > > explicit stack( size_type n ) : pool( node_allocator(), n ) { - // Don't use BOOST_STATIC_ASSERT() here since it will be evaluated when compiling - // this function and this function may be compiled even when it isn't being used. - BOOST_ASSERT( !has_capacity ); initialize(); } + stack( const stack& ) = delete; + stack& operator=( const stack& ) = delete; + stack( stack&& ) = delete; + stack& operator=( stack&& ) = delete; + + /** Construct a variable-sized stack with a custom allocator * * Allocate n nodes initially for the freelist * * \pre Must \b not specify a capacity<> argument * */ - template < typename U > + template < typename U, typename Enabler = std::enable_if< !has_capacity > > stack( size_type n, typename boost::allocator_rebind< node_allocator, U >::type const& alloc ) : pool( alloc, n ) { - BOOST_STATIC_ASSERT( !has_capacity ); initialize(); } @@ -206,10 +195,10 @@ class stack * * \pre Must \b not specify a capacity<> argument * */ + template < typename Enabler = std::enable_if< !has_capacity > > stack( size_type n, node_allocator const& alloc ) : pool( alloc, n ) { - BOOST_STATIC_ASSERT( !has_capacity ); initialize(); } @@ -219,11 +208,9 @@ class stack * \note thread-safe, may block if memory allocator blocks * * */ + template < typename Enabler = std::enable_if< !has_capacity > > void reserve( size_type n ) { - // Don't use BOOST_STATIC_ASSERT() here since it will be evaluated when compiling - // this function and this function may be compiled even when it isn't being used. - BOOST_ASSERT( !has_capacity ); pool.template reserve< true >( n ); } @@ -233,11 +220,9 @@ class stack * \note not thread-safe, may block if memory allocator blocks * * */ + template < typename Enabler = std::enable_if< !has_capacity > > void reserve_unsafe( size_type n ) { - // Don't use BOOST_STATIC_ASSERT() here since it will be evaluated when compiling - // this function and this function may be compiled even when it isn't being used. - BOOST_ASSERT( !has_capacity ); pool.template reserve< false >( n ); } @@ -248,8 +233,7 @@ class stack * */ ~stack( void ) { - detail::consume_noop consume_functor; - (void)consume_all( consume_functor ); + consume_all( []( const T& ) {} ); } private: @@ -282,13 +266,13 @@ class stack } template < bool Threadsafe, bool Bounded, typename ConstIterator > - tuple< node*, node* > prepare_node_list( ConstIterator begin, ConstIterator end, ConstIterator& ret ) + std::tuple< node*, node* > prepare_node_list( ConstIterator begin, ConstIterator end, ConstIterator& ret ) { ConstIterator it = begin; node* end_node = pool.template construct< Threadsafe, Bounded >( *it++ ); if ( end_node == NULL ) { ret = begin; - return make_tuple< node*, node* >( NULL, NULL ); + return std::make_tuple< node*, node* >( NULL, NULL ); } node* new_top_node = end_node; @@ -317,7 +301,32 @@ class stack BOOST_CATCH_END ret = it; - return make_tuple( new_top_node, end_node ); + return std::make_tuple( new_top_node, end_node ); + } + + template < bool Bounded > + bool do_push( T const& v ) + { + node* newnode = pool.template construct< true, Bounded >( v ); + if ( newnode == 0 ) + return false; + + link_nodes_atomic( newnode, newnode ); + return true; + } + + template < bool Bounded, typename ConstIterator > + ConstIterator do_push( ConstIterator begin, ConstIterator end ) + { + node* new_top_node; + node* end_node; + ConstIterator ret; + + std::tie( new_top_node, end_node ) = prepare_node_list< true, Bounded >( begin, end, ret ); + if ( new_top_node ) + link_nodes_atomic( new_top_node, end_node ); + + return ret; } #endif @@ -347,43 +356,15 @@ class stack return do_push< true >( v ); } -#ifndef BOOST_DOXYGEN_INVOKED -private: - template < bool Bounded > - bool do_push( T const& v ) - { - node* newnode = pool.template construct< true, Bounded >( v ); - if ( newnode == 0 ) - return false; - - link_nodes_atomic( newnode, newnode ); - return true; - } - - template < bool Bounded, typename ConstIterator > - ConstIterator do_push( ConstIterator begin, ConstIterator end ) - { - node* new_top_node; - node* end_node; - ConstIterator ret; - - tie( new_top_node, end_node ) = prepare_node_list< true, Bounded >( begin, end, ret ); - if ( new_top_node ) - link_nodes_atomic( new_top_node, end_node ); - - return ret; - } - -public: -#endif - /** Pushes as many objects from the range [begin, end) as freelist node can be allocated. * * \return iterator to the first element, which has not been pushed * * \note Operation is applied atomically * \note Thread-safe. If internal memory pool is exhausted and the memory pool is not fixed-sized, a new node will - * be allocated from the OS. This may not be lock-free. \throws if memory allocator throws + * be allocated from the OS. This may not be lock-free. + * + * \throws if memory allocator throws */ template < typename ConstIterator > ConstIterator push( ConstIterator begin, ConstIterator end ) @@ -391,6 +372,23 @@ class stack return do_push< false, ConstIterator >( begin, end ); } + /** Pushes as many objects from the span as freelist node can be allocated. + * + * \return Number of elements pushed + * + * \note Operation is applied atomically + * \note Thread-safe. If internal memory pool is exhausted and the memory pool is not fixed-sized, a new node will + * be allocated from the OS. This may not be lock-free. + * + * \throws if memory allocator throws + */ + template < std::size_t Extent > + size_type push( boost::span< const T, Extent > t ) + { + const T* end_pushed = push( t.begin(), t.end() ); + return std::distance( t.begin(), end_pushed ); + } + /** Pushes as many objects from the range [begin, end) as freelist node can be allocated. * * \return iterator to the first element, which has not been pushed @@ -405,6 +403,21 @@ class stack return do_push< true, ConstIterator >( begin, end ); } + /** Pushes as many objects from the span as freelist node can be allocated. + * + * \return Number of elements pushed + * + * \note Operation is applied atomically + * \note Thread-safe and non-blocking. If internal memory pool is exhausted, the push operation will fail + * \throws if memory allocator throws + */ + template < std::size_t Extent > + size_type bounded_push( boost::span< const T, Extent > t ) + { + const T* end_pushed = bounded_push( t.begin(), t.end() ); + return std::distance( t.begin(), end_pushed ); + } + /** Pushes object t to the stack. * @@ -412,7 +425,8 @@ class stack * \returns true, if the push operation is successful. * * \note Not thread-safe. If internal memory pool is exhausted and the memory pool is not fixed-sized, a new node - * will be allocated from the OS. This may not be lock-free. \throws if memory allocator throws + * will be allocated from the OS. This may not be lock-free. + * \throws if memory allocator throws * */ bool unsynchronized_push( T const& v ) { @@ -429,7 +443,8 @@ class stack * \return iterator to the first element, which has not been pushed * * \note Not thread-safe. If internal memory pool is exhausted and the memory pool is not fixed-sized, a new node - * will be allocated from the OS. This may not be lock-free. \throws if memory allocator throws + * will be allocated from the OS. This may not be lock-free. + * \throws if memory allocator throws */ template < typename ConstIterator > ConstIterator unsynchronized_push( ConstIterator begin, ConstIterator end ) @@ -438,13 +453,26 @@ class stack node* end_node; ConstIterator ret; - tie( new_top_node, end_node ) = prepare_node_list< false, false >( begin, end, ret ); + std::tie( new_top_node, end_node ) = prepare_node_list< false, false >( begin, end, ret ); if ( new_top_node ) link_nodes_unsafe( new_top_node, end_node ); return ret; } + /** Pushes as many objects from the span as freelist node can be allocated. + * + * \return iterator to the first element, which has not been pushed + * + * \note Not thread-safe. If internal memory pool is exhausted and the memory pool is not fixed-sized, a new node + * will be allocated from the OS. This may not be lock-free. \throws if memory allocator throws + */ + template < std::size_t Extent > + size_type unsynchronized_push( boost::span< const T, Extent > t ) + { + const T* end_pushed = unsynchronized_push( t.begin(), t.end() ); + return std::distance( t.begin(), end_pushed ); + } /** Pops object from stack. * @@ -468,13 +496,12 @@ class stack * \note Thread-safe and non-blocking * * */ - template < typename U > + template < typename U, typename Enabler = std::enable_if< std::is_convertible< T, U >::value > > bool pop( U& ret ) { - BOOST_STATIC_ASSERT( ( boost::is_convertible< T, U >::value ) ); - detail::consume_via_copy< U > consumer( ret ); - - return consume_one( consumer ); + return consume_one( [ & ]( const T& t ) { + ret = U( t ); + } ); } @@ -500,10 +527,9 @@ class stack * \note Not thread-safe, but non-blocking * * */ - template < typename U > + template < typename U, typename Enabler = std::enable_if< std::is_convertible< T, U >::value > > bool unsynchronized_pop( U& ret ) { - BOOST_STATIC_ASSERT( ( boost::is_convertible< T, U >::value ) ); tagged_node_handle old_tos = tos.load( detail::memory_order_relaxed ); node* old_tos_pointer = pool.get_pointer( old_tos ); @@ -528,28 +554,7 @@ class stack * \note Thread-safe and non-blocking, if functor is thread-safe and non-blocking * */ template < typename Functor > - bool consume_one( Functor& f ) - { - tagged_node_handle old_tos = tos.load( detail::memory_order_consume ); - - for ( ;; ) { - node* old_tos_pointer = pool.get_pointer( old_tos ); - if ( !old_tos_pointer ) - return false; - - tagged_node_handle new_tos( old_tos_pointer->next, old_tos.get_next_tag() ); - - if ( tos.compare_exchange_weak( old_tos, new_tos ) ) { - f( old_tos_pointer->v ); - pool.template destruct< true >( old_tos ); - return true; - } - } - } - - /// \copydoc boost::lockfree::stack::consume_one(Functor & rhs) - template < typename Functor > - bool consume_one( Functor const& f ) + bool consume_one( Functor&& f ) { tagged_node_handle old_tos = tos.load( detail::memory_order_consume ); @@ -577,18 +582,7 @@ class stack * \note Thread-safe and non-blocking, if functor is thread-safe and non-blocking * */ template < typename Functor > - size_t consume_all( Functor& f ) - { - size_t element_count = 0; - while ( consume_one( f ) ) - element_count += 1; - - return element_count; - } - - /// \copydoc boost::lockfree::stack::consume_all(Functor & rhs) - template < typename Functor > - size_t consume_all( Functor const& f ) + size_t consume_all( Functor&& f ) { size_t element_count = 0; while ( consume_one( f ) ) @@ -606,47 +600,7 @@ class stack * \note Thread-safe and non-blocking, if functor is thread-safe and non-blocking * */ template < typename Functor > - size_t consume_all_atomic( Functor& f ) - { - size_t element_count = 0; - tagged_node_handle old_tos = tos.load( detail::memory_order_consume ); - - for ( ;; ) { - node* old_tos_pointer = pool.get_pointer( old_tos ); - if ( !old_tos_pointer ) - return 0; - - tagged_node_handle new_tos( pool.null_handle(), old_tos.get_next_tag() ); - - if ( tos.compare_exchange_weak( old_tos, new_tos ) ) - break; - } - - tagged_node_handle nodes_to_consume = old_tos; - - for ( ;; ) { - node* node_pointer = pool.get_pointer( nodes_to_consume ); - f( node_pointer->v ); - element_count += 1; - - node* next_node = pool.get_pointer( node_pointer->next ); - - if ( !next_node ) { - pool.template destruct< true >( nodes_to_consume ); - break; - } - - tagged_node_handle next( pool.get_handle( next_node ), nodes_to_consume.get_next_tag() ); - pool.template destruct< true >( nodes_to_consume ); - nodes_to_consume = next; - } - - return element_count; - } - - /// \copydoc boost::lockfree::stack::consume_all_atomic(Functor & rhs) - template < typename Functor > - size_t consume_all_atomic( Functor const& f ) + size_t consume_all_atomic( Functor&& f ) { size_t element_count = 0; tagged_node_handle old_tos = tos.load( detail::memory_order_consume ); @@ -693,65 +647,7 @@ class stack * \note Thread-safe and non-blocking, if functor is thread-safe and non-blocking * */ template < typename Functor > - size_t consume_all_atomic_reversed( Functor& f ) - { - size_t element_count = 0; - tagged_node_handle old_tos = tos.load( detail::memory_order_consume ); - - for ( ;; ) { - node* old_tos_pointer = pool.get_pointer( old_tos ); - if ( !old_tos_pointer ) - return 0; - - tagged_node_handle new_tos( pool.null_handle(), old_tos.get_next_tag() ); - - if ( tos.compare_exchange_weak( old_tos, new_tos ) ) - break; - } - - tagged_node_handle nodes_to_consume = old_tos; - - node* last_node_pointer = NULL; - tagged_node_handle nodes_in_reversed_order; - for ( ;; ) { - node* node_pointer = pool.get_pointer( nodes_to_consume ); - node* next_node = pool.get_pointer( node_pointer->next ); - - node_pointer->next = pool.get_handle( last_node_pointer ); - last_node_pointer = node_pointer; - - if ( !next_node ) { - nodes_in_reversed_order = nodes_to_consume; - break; - } - - tagged_node_handle next( pool.get_handle( next_node ), nodes_to_consume.get_next_tag() ); - nodes_to_consume = next; - } - - for ( ;; ) { - node* node_pointer = pool.get_pointer( nodes_in_reversed_order ); - f( node_pointer->v ); - element_count += 1; - - node* next_node = pool.get_pointer( node_pointer->next ); - - if ( !next_node ) { - pool.template destruct< true >( nodes_in_reversed_order ); - break; - } - - tagged_node_handle next( pool.get_handle( next_node ), nodes_in_reversed_order.get_next_tag() ); - pool.template destruct< true >( nodes_in_reversed_order ); - nodes_in_reversed_order = next; - } - - return element_count; - } - - /// \copydoc boost::lockfree::stack::consume_all_atomic_reversed(Functor & rhs) - template < typename Functor > - size_t consume_all_atomic_reversed( Functor const& f ) + size_t consume_all_atomic_reversed( Functor&& f ) { size_t element_count = 0; tagged_node_handle old_tos = tos.load( detail::memory_order_consume ); diff --git a/meta/libraries.json b/meta/libraries.json index 30082ed6..ede88f26 100644 --- a/meta/libraries.json +++ b/meta/libraries.json @@ -11,5 +11,5 @@ "maintainers": [ "Tim Blechmann " ], - "cxxstd": "03" + "cxxstd": "14" } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 1a3ec2a4..e0add4c0 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -37,8 +37,8 @@ foreach(Test ${Tests}) Boost::lockfree Boost::unit_test_framework Boost::thread - Boost::foreach ) + set_target_properties( boost_lockfree_${Test} PROPERTIES CMAKE_CXX_STANDARD_REQUIRED 14) target_compile_definitions(boost_lockfree_${Test} PRIVATE BOOST_TEST_NO_OLD_TOOLS ) diff --git a/test/freelist_test.cpp b/test/freelist_test.cpp index 02990b39..9aa1e7ec 100644 --- a/test/freelist_test.cpp +++ b/test/freelist_test.cpp @@ -10,9 +10,7 @@ #include #include -#include -#include -#include +#include #define BOOST_TEST_MAIN #ifdef BOOST_LOCKFREE_INCLUDE_TESTS @@ -66,14 +64,14 @@ void run_test( void ) nodes.insert( allocated ); } - BOOST_FOREACH ( dummy* d, nodes ) + for ( dummy* d : nodes ) fl.template destruct< threadsafe >( d ); nodes.clear(); for ( int i = 0; i != 4; ++i ) nodes.insert( fl.template construct< threadsafe, bounded >() ); - BOOST_FOREACH ( dummy* d, nodes ) + for ( dummy* d : nodes ) fl.template destruct< threadsafe >( d ); for ( int i = 0; i != 4; ++i ) @@ -152,10 +150,14 @@ struct freelist_tester boost::thread_group dealloc_threads; for ( int i = 0; i != thread_count; ++i ) - dealloc_threads.create_thread( boost::bind( &freelist_tester::deallocate, this ) ); + dealloc_threads.create_thread( [ this ] { + deallocate(); + } ); for ( int i = 0; i != thread_count; ++i ) - alloc_threads.create_thread( boost::bind( &freelist_tester::allocate, this ) ); + alloc_threads.create_thread( [ this ] { + allocate(); + } ); alloc_threads.join_all(); test_running.store( false ); running = false; @@ -193,7 +195,7 @@ struct freelist_tester break; #ifdef __VXWORKS__ - boost::thread::yield(); + std::this_thread::yield(); #endif } @@ -210,7 +212,7 @@ struct freelist_tester template < typename Tester > void run_tester() { - boost::scoped_ptr< Tester > tester( new Tester ); + std::unique_ptr< Tester > tester( new Tester ); tester->run(); } diff --git a/test/queue_bounded_stress_test.cpp b/test/queue_bounded_stress_test.cpp index bdd1db1e..5a1e689f 100644 --- a/test/queue_bounded_stress_test.cpp +++ b/test/queue_bounded_stress_test.cpp @@ -6,8 +6,6 @@ #include -#include - #define BOOST_TEST_MAIN #ifdef BOOST_LOCKFREE_INCLUDE_TESTS # include @@ -20,7 +18,7 @@ BOOST_AUTO_TEST_CASE( queue_test_bounded ) { typedef queue_stress_tester< true > tester_type; - boost::scoped_ptr< tester_type > tester( new tester_type( 4, 4 ) ); + std::unique_ptr< tester_type > tester( new tester_type( 4, 4 ) ); boost::lockfree::queue< long > q( 128 ); tester->run( q ); diff --git a/test/queue_fixedsize_stress_test.cpp b/test/queue_fixedsize_stress_test.cpp index 944bf1ae..f1aa10ce 100644 --- a/test/queue_fixedsize_stress_test.cpp +++ b/test/queue_fixedsize_stress_test.cpp @@ -6,8 +6,6 @@ #include -#include - #define BOOST_TEST_MAIN #ifdef BOOST_LOCKFREE_INCLUDE_TESTS # include @@ -20,8 +18,8 @@ BOOST_AUTO_TEST_CASE( queue_test_fixed_size ) { - typedef queue_stress_tester<> tester_type; - boost::scoped_ptr< tester_type > tester( new tester_type( 4, 4 ) ); + typedef queue_stress_tester<> tester_type; + std::unique_ptr< tester_type > tester( new tester_type( 4, 4 ) ); boost::lockfree::queue< long, boost::lockfree::capacity< 8 > > q; tester->run( q ); diff --git a/test/queue_interprocess_test.cpp b/test/queue_interprocess_test.cpp index eb227417..537ab8cf 100644 --- a/test/queue_interprocess_test.cpp +++ b/test/queue_interprocess_test.cpp @@ -4,11 +4,11 @@ // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -#include //std::system +#include +#include #include #include -#include using namespace boost::interprocess; typedef allocator< int, managed_shared_memory::segment_manager > ShmemAllocator; @@ -42,7 +42,7 @@ int main( int argc, char* argv[] ) return 1; while ( !q->empty() ) - boost::thread::yield(); + std::this_thread::yield(); return 0; } else { managed_shared_memory segment( open_only, "boost_queue_interprocess_test_shm" ); diff --git a/test/queue_test.cpp b/test/queue_test.cpp index aebb05f2..eb603d50 100644 --- a/test/queue_test.cpp +++ b/test/queue_test.cpp @@ -95,18 +95,13 @@ BOOST_AUTO_TEST_CASE( queue_consume_one_test ) f.push( 1 ); f.push( 2 ); -#ifdef BOOST_NO_CXX11_LAMBDAS - bool success1 = f.consume_one( test_equal( 1 ) ); - bool success2 = f.consume_one( test_equal( 2 ) ); -#else bool success1 = f.consume_one( []( int i ) { BOOST_TEST_REQUIRE( i == 1 ); } ); - bool success2 = f.consume_one( []( int i ) { + bool success2 = f.consume_one( []( int i ) mutable { BOOST_TEST_REQUIRE( i == 2 ); } ); -#endif BOOST_TEST_REQUIRE( success1 ); BOOST_TEST_REQUIRE( success2 ); @@ -124,11 +119,7 @@ BOOST_AUTO_TEST_CASE( queue_consume_all_test ) f.push( 1 ); f.push( 2 ); -#ifdef BOOST_NO_CXX11_LAMBDAS - size_t consumed = f.consume_all( dummy_functor() ); -#else size_t consumed = f.consume_all( []( int i ) {} ); -#endif BOOST_TEST_REQUIRE( consumed == 2u ); @@ -161,18 +152,14 @@ BOOST_AUTO_TEST_CASE( queue_convert_pop_test ) } { -#ifdef BOOST_NO_AUTO_PTR unique_ptr< int > i3; -#else - auto_ptr< int > i3; -#endif BOOST_TEST_REQUIRE( f.pop( i3 ) ); BOOST_TEST_REQUIRE( *i3 == 3 ); } { - boost::shared_ptr< int > i4; + std::shared_ptr< int > i4; BOOST_TEST_REQUIRE( f.pop( i4 ) ); BOOST_TEST_REQUIRE( *i4 == 4 ); diff --git a/test/queue_unbounded_stress_test.cpp b/test/queue_unbounded_stress_test.cpp index 1b00119b..cd593001 100644 --- a/test/queue_unbounded_stress_test.cpp +++ b/test/queue_unbounded_stress_test.cpp @@ -6,8 +6,6 @@ #include -#include - #define BOOST_TEST_MAIN #ifdef BOOST_LOCKFREE_INCLUDE_TESTS # include @@ -20,7 +18,7 @@ BOOST_AUTO_TEST_CASE( queue_test_unbounded ) { typedef queue_stress_tester< false > tester_type; - boost::scoped_ptr< tester_type > tester( new tester_type( 4, 4 ) ); + std::unique_ptr< tester_type > tester( new tester_type( 4, 4 ) ); boost::lockfree::queue< long > q( 128 ); tester->run( q ); diff --git a/test/spsc_queue_stress_test.cpp b/test/spsc_queue_stress_test.cpp index 45d15bdf..bfb60cd2 100644 --- a/test/spsc_queue_stress_test.cpp +++ b/test/spsc_queue_stress_test.cpp @@ -5,7 +5,6 @@ // http://www.boost.org/LICENSE_1_0.txt) #include -#include #define BOOST_TEST_MAIN #ifdef BOOST_LOCKFREE_INCLUDE_TESTS @@ -14,8 +13,10 @@ # include #endif +#include +#include #include -#include +#include #include "test_common.hpp" #include "test_helpers.hpp" @@ -34,7 +35,7 @@ struct spsc_queue_tester { spsc_queue< int, capacity< 128 > > sf; - boost::lockfree::detail::atomic< long > spsc_queue_cnt, received_nodes; + std::atomic< long > spsc_queue_cnt, received_nodes; // In VxWorks one RTP just supports 65535 objects #ifndef __VXWORKS__ @@ -77,7 +78,7 @@ struct spsc_queue_tester return false; } - boost::lockfree::detail::atomic< bool > running; + std::atomic< bool > running; void get( void ) { @@ -97,8 +98,13 @@ struct spsc_queue_tester BOOST_TEST_REQUIRE( sf.empty() ); - boost::thread reader( boost::bind( &spsc_queue_tester::get, this ) ); - boost::thread writer( boost::bind( &spsc_queue_tester::add, this ) ); + std::thread reader( [ & ] { + get(); + } ); + + std::thread writer( [ & ] { + add(); + } ); cout << "reader and writer threads created" << endl; writer.join(); @@ -115,7 +121,7 @@ struct spsc_queue_tester BOOST_AUTO_TEST_CASE( spsc_queue_test_caching ) { - boost::shared_ptr< spsc_queue_tester > test1( new spsc_queue_tester ); + std::shared_ptr< spsc_queue_tester > test1( new spsc_queue_tester ); test1->run(); } @@ -123,7 +129,7 @@ struct spsc_queue_tester_buffering { spsc_queue< int, capacity< 128 > > sf; - boost::lockfree::detail::atomic< long > spsc_queue_cnt; + std::atomic< long > spsc_queue_cnt; // In VxWorks one RTP just supports 65535 objects #ifndef __VXWORKS__ @@ -132,7 +138,7 @@ struct spsc_queue_tester_buffering static_hashed_set< int, 1 << 15 > working_set; #endif - boost::lockfree::detail::atomic< size_t > received_nodes; + std::atomic< size_t > received_nodes; spsc_queue_tester_buffering( void ) : spsc_queue_cnt( 0 ), @@ -143,7 +149,7 @@ struct spsc_queue_tester_buffering void add( void ) { - boost::array< int, buf_size > input_buffer; + std::array< int, buf_size > input_buffer; for ( size_t i = 0; i != nodes_per_thread; i += buf_size ) { for ( size_t i = 0; i != buf_size; ++i ) { int id = generate_id< int >(); @@ -154,7 +160,7 @@ struct spsc_queue_tester_buffering size_t pushed = 0; do { - pushed += sf.push( input_buffer.c_array() + pushed, input_buffer.size() - pushed ); + pushed += sf.push( input_buffer.data() + pushed, input_buffer.size() - pushed ); } while ( pushed != buf_size ); spsc_queue_cnt += buf_size; @@ -164,9 +170,9 @@ struct spsc_queue_tester_buffering bool get_elements( void ) { - boost::array< int, buf_size > output_buffer; + std::array< int, buf_size > output_buffer; - size_t popd = sf.pop( output_buffer.c_array(), output_buffer.size() ); + size_t popd = sf.pop( output_buffer.data(), output_buffer.size() ); if ( popd ) { received_nodes += size_t( popd ); @@ -183,7 +189,7 @@ struct spsc_queue_tester_buffering return false; } - boost::lockfree::detail::atomic< bool > running; + std::atomic< bool > running; void get( void ) { @@ -201,8 +207,14 @@ struct spsc_queue_tester_buffering { running = true; - boost::thread reader( boost::bind( &spsc_queue_tester_buffering::get, this ) ); - boost::thread writer( boost::bind( &spsc_queue_tester_buffering::add, this ) ); + std::thread reader( [ & ] { + get(); + } ); + + std::thread writer( [ & ] { + add(); + } ); + cout << "reader and writer threads created" << endl; writer.join(); @@ -220,6 +232,6 @@ struct spsc_queue_tester_buffering BOOST_AUTO_TEST_CASE( spsc_queue_test_buffering ) { - boost::shared_ptr< spsc_queue_tester_buffering > test1( new spsc_queue_tester_buffering ); + std::shared_ptr< spsc_queue_tester_buffering > test1( new spsc_queue_tester_buffering ); test1->run(); } diff --git a/test/spsc_queue_test.cpp b/test/spsc_queue_test.cpp index 2a8cb324..76fa429a 100644 --- a/test/spsc_queue_test.cpp +++ b/test/spsc_queue_test.cpp @@ -13,11 +13,7 @@ # include #endif -#include -#include - #include "test_common.hpp" -#include "test_helpers.hpp" using namespace boost; using namespace boost::lockfree; @@ -85,10 +81,6 @@ BOOST_AUTO_TEST_CASE( spsc_queue_consume_one_test ) f.push( 1 ); f.push( 2 ); -#ifdef BOOST_NO_CXX11_LAMBDAS - bool success1 = f.consume_one( test_equal( 1 ) ); - bool success2 = f.consume_one( test_equal( 2 ) ); -#else bool success1 = f.consume_one( []( int i ) { BOOST_TEST_REQUIRE( i == 1 ); } ); @@ -96,7 +88,6 @@ BOOST_AUTO_TEST_CASE( spsc_queue_consume_one_test ) bool success2 = f.consume_one( []( int i ) { BOOST_TEST_REQUIRE( i == 2 ); } ); -#endif BOOST_TEST_REQUIRE( success1 ); BOOST_TEST_REQUIRE( success2 ); @@ -114,11 +105,7 @@ BOOST_AUTO_TEST_CASE( spsc_queue_consume_all_test ) f.push( 1 ); f.push( 2 ); -#ifdef BOOST_NO_CXX11_LAMBDAS - size_t consumed = f.consume_all( dummy_functor() ); -#else size_t consumed = f.consume_all( []( int i ) {} ); -#endif BOOST_TEST_REQUIRE( consumed == 2u ); @@ -130,6 +117,7 @@ enum pointer_and_size, reference_to_array, iterator_pair, + span_, output_iterator_ }; @@ -196,19 +184,18 @@ void spsc_queue_buffer_push_return_value( void ) switch ( EnqueueMode ) { case pointer_and_size: BOOST_TEST_REQUIRE( rb.push( data, xqueue_size ) == xqueue_size ); break; - case reference_to_array: BOOST_TEST_REQUIRE( rb.push( data ) == xqueue_size ); break; - case iterator_pair: BOOST_TEST_REQUIRE( rb.push( data, data + xqueue_size ) == data + xqueue_size ); break; - + case span_: BOOST_TEST_REQUIRE( rb.push( boost::span< const int >( data, xqueue_size ) ) == xqueue_size ); break; default: assert( false ); } switch ( EnqueueMode ) { case pointer_and_size: BOOST_TEST_REQUIRE( rb.push( data, xqueue_size ) == buffer_size - xqueue_size ); break; - case reference_to_array: BOOST_TEST_REQUIRE( rb.push( data ) == buffer_size - xqueue_size ); break; - + case span_: + BOOST_TEST_REQUIRE( rb.push( boost::span< const int >( data, xqueue_size ) ) == buffer_size - xqueue_size ); + break; case iterator_pair: BOOST_TEST_REQUIRE( rb.push( data, data + xqueue_size ) == data + buffer_size - xqueue_size ); break; @@ -222,6 +209,7 @@ BOOST_AUTO_TEST_CASE( spsc_queue_buffer_push_return_value_test ) spsc_queue_buffer_push_return_value< pointer_and_size >(); spsc_queue_buffer_push_return_value< reference_to_array >(); spsc_queue_buffer_push_return_value< iterator_pair >(); + spsc_queue_buffer_push_return_value< span_ >(); } template < int EnqueueMode, int ElementCount, int BufferSize, int NumberOfIterations > @@ -240,12 +228,13 @@ void spsc_queue_buffer_push( void ) BOOST_TEST_REQUIRE( rb.empty() ); switch ( EnqueueMode ) { case pointer_and_size: BOOST_TEST_REQUIRE( rb.push( data, xqueue_size ) == xqueue_size ); break; - case reference_to_array: BOOST_TEST_REQUIRE( rb.push( data ) == xqueue_size ); break; - case iterator_pair: BOOST_TEST_REQUIRE( rb.push( data, data + xqueue_size ) == data + xqueue_size ); break; + case span_: + BOOST_TEST_REQUIRE( rb.push( boost::span< const int >( data, xqueue_size ) ) == xqueue_size ); + break; - default: assert( false ); + default: assert( false ); } int out[ xqueue_size ]; @@ -260,6 +249,7 @@ BOOST_AUTO_TEST_CASE( spsc_queue_buffer_push_test ) spsc_queue_buffer_push< pointer_and_size, 7, 16, 64 >(); spsc_queue_buffer_push< reference_to_array, 7, 16, 64 >(); spsc_queue_buffer_push< iterator_pair, 7, 16, 64 >(); + spsc_queue_buffer_push< span_, 7, 16, 64 >(); } template < int EnqueueMode, int ElementCount, int BufferSize, int NumberOfIterations > @@ -283,11 +273,8 @@ void spsc_queue_buffer_pop( void ) switch ( EnqueueMode ) { case pointer_and_size: BOOST_TEST_REQUIRE( rb.pop( out, xqueue_size ) == xqueue_size ); break; - case reference_to_array: BOOST_TEST_REQUIRE( rb.pop( out ) == xqueue_size ); break; - case output_iterator_: BOOST_TEST_REQUIRE( rb.pop( std::back_inserter( vout ) ) == xqueue_size ); break; - default: assert( false ); } diff --git a/test/stack_bounded_stress_test.cpp b/test/stack_bounded_stress_test.cpp index 05037811..d74ebe5c 100644 --- a/test/stack_bounded_stress_test.cpp +++ b/test/stack_bounded_stress_test.cpp @@ -6,7 +6,7 @@ #include -#include +#include #define BOOST_TEST_MAIN #ifdef BOOST_LOCKFREE_INCLUDE_TESTS @@ -20,7 +20,7 @@ BOOST_AUTO_TEST_CASE( stack_test_bounded ) { typedef queue_stress_tester< true > tester_type; - boost::scoped_ptr< tester_type > tester( new tester_type( 4, 4 ) ); + std::unique_ptr< tester_type > tester( new tester_type( 4, 4 ) ); boost::lockfree::stack< long > q( 128 ); tester->run( q ); diff --git a/test/stack_fixedsize_stress_test.cpp b/test/stack_fixedsize_stress_test.cpp index 458f1a0f..21c72406 100644 --- a/test/stack_fixedsize_stress_test.cpp +++ b/test/stack_fixedsize_stress_test.cpp @@ -6,8 +6,6 @@ #include -#include - #define BOOST_TEST_MAIN #ifdef BOOST_LOCKFREE_INCLUDE_TESTS # include @@ -20,8 +18,8 @@ BOOST_AUTO_TEST_CASE( stack_test_fixed_size ) { - typedef queue_stress_tester<> tester_type; - boost::scoped_ptr< tester_type > tester( new tester_type( 4, 4 ) ); + typedef queue_stress_tester<> tester_type; + std::unique_ptr< tester_type > tester( new tester_type( 4, 4 ) ); boost::lockfree::stack< long, boost::lockfree::capacity< 8 > > q; tester->run( q ); diff --git a/test/stack_interprocess_test.cpp b/test/stack_interprocess_test.cpp index aa39c524..15813d25 100644 --- a/test/stack_interprocess_test.cpp +++ b/test/stack_interprocess_test.cpp @@ -5,10 +5,10 @@ // http://www.boost.org/LICENSE_1_0.txt) #include //std::system +#include #include #include -#include using namespace boost::interprocess; typedef allocator< int, managed_shared_memory::segment_manager > ShmemAllocator; @@ -42,7 +42,7 @@ int main( int argc, char* argv[] ) return 1; while ( !queue->empty() ) - boost::thread::yield(); + std::this_thread::yield(); return 0; } else { managed_shared_memory segment( open_only, "MySharedMemory" ); diff --git a/test/stack_test.cpp b/test/stack_test.cpp index 9f323c9e..b8fc4dba 100644 --- a/test/stack_test.cpp +++ b/test/stack_test.cpp @@ -6,7 +6,6 @@ #include -#include #define BOOST_TEST_MAIN #ifdef BOOST_LOCKFREE_INCLUDE_TESTS @@ -15,8 +14,6 @@ # include #endif -#include "test_helpers.hpp" - BOOST_AUTO_TEST_CASE( simple_stack_test ) { boost::lockfree::stack< long > stk( 128 ); @@ -61,6 +58,23 @@ BOOST_AUTO_TEST_CASE( ranged_push_test ) BOOST_TEST_REQUIRE( !stk.unsynchronized_pop( out ) ); } +BOOST_AUTO_TEST_CASE( span_push_test ) +{ + boost::lockfree::stack< long > stk( 128 ); + + long data[ 2 ] = { 1, 2 }; + + BOOST_TEST_REQUIRE( stk.push( boost::span< const long >( data ) ) == 2 ); + + long out; + BOOST_TEST_REQUIRE( stk.unsynchronized_pop( out ) ); + BOOST_TEST_REQUIRE( out == 2 ); + BOOST_TEST_REQUIRE( stk.unsynchronized_pop( out ) ); + BOOST_TEST_REQUIRE( out == 1 ); + BOOST_TEST_REQUIRE( !stk.unsynchronized_pop( out ) ); +} + + BOOST_AUTO_TEST_CASE( ranged_unsynchronized_push_test ) { boost::lockfree::stack< long > stk( 128 ); @@ -77,6 +91,23 @@ BOOST_AUTO_TEST_CASE( ranged_unsynchronized_push_test ) BOOST_TEST_REQUIRE( !stk.unsynchronized_pop( out ) ); } +BOOST_AUTO_TEST_CASE( span_unsynchronized_push_test ) +{ + boost::lockfree::stack< long > stk( 128 ); + + long data[ 2 ] = { 1, 2 }; + + BOOST_TEST_REQUIRE( stk.unsynchronized_push( boost::span< const long >( data ) ) == 2 ); + + long out; + BOOST_TEST_REQUIRE( stk.unsynchronized_pop( out ) ); + BOOST_TEST_REQUIRE( out == 2 ); + BOOST_TEST_REQUIRE( stk.unsynchronized_pop( out ) ); + BOOST_TEST_REQUIRE( out == 1 ); + BOOST_TEST_REQUIRE( !stk.unsynchronized_pop( out ) ); +} + + BOOST_AUTO_TEST_CASE( fixed_size_stack_test ) { boost::lockfree::stack< long, boost::lockfree::capacity< 128 > > stk; @@ -134,18 +165,13 @@ BOOST_AUTO_TEST_CASE( stack_consume_one_test ) f.push( 1 ); f.push( 2 ); -#ifdef BOOST_NO_CXX11_LAMBDAS - bool success1 = f.consume_one( test_equal( 2 ) ); - bool success2 = f.consume_one( test_equal( 1 ) ); -#else bool success1 = f.consume_one( []( int i ) { BOOST_TEST_REQUIRE( i == 2 ); } ); - bool success2 = f.consume_one( []( int i ) { + bool success2 = f.consume_one( []( int i ) mutable { BOOST_TEST_REQUIRE( i == 1 ); } ); -#endif BOOST_TEST_REQUIRE( success1 ); BOOST_TEST_REQUIRE( success2 ); @@ -163,11 +189,7 @@ BOOST_AUTO_TEST_CASE( stack_consume_all_test ) f.push( 1 ); f.push( 2 ); -#ifdef BOOST_NO_CXX11_LAMBDAS - size_t consumed = f.consume_all( dummy_functor() ); -#else size_t consumed = f.consume_all( []( int i ) {} ); -#endif BOOST_TEST_REQUIRE( consumed == 2u ); @@ -185,11 +207,7 @@ BOOST_AUTO_TEST_CASE( stack_consume_all_atomic_test ) f.push( 2 ); f.push( 3 ); -#ifdef BOOST_NO_CXX11_LAMBDAS - size_t consumed = f.consume_all_atomic( dummy_functor() ); -#else size_t consumed = f.consume_all_atomic( []( int i ) {} ); -#endif BOOST_TEST_REQUIRE( consumed == 3u ); @@ -208,11 +226,7 @@ BOOST_AUTO_TEST_CASE( stack_consume_all_atomic_reversed_test ) f.push( 2 ); f.push( 3 ); -#ifdef BOOST_NO_CXX11_LAMBDAS - size_t consumed = f.consume_all_atomic_reversed( dummy_functor() ); -#else size_t consumed = f.consume_all_atomic_reversed( []( int i ) {} ); -#endif BOOST_TEST_REQUIRE( consumed == 3u ); diff --git a/test/stack_unbounded_stress_test.cpp b/test/stack_unbounded_stress_test.cpp index a922680a..05e9c157 100644 --- a/test/stack_unbounded_stress_test.cpp +++ b/test/stack_unbounded_stress_test.cpp @@ -6,8 +6,6 @@ #include -#include - #define BOOST_TEST_MAIN #ifdef BOOST_LOCKFREE_INCLUDE_TESTS # include @@ -21,7 +19,7 @@ BOOST_AUTO_TEST_CASE( stack_test_unbounded ) { typedef queue_stress_tester< false > tester_type; - boost::scoped_ptr< tester_type > tester( new tester_type( 4, 4 ) ); + std::unique_ptr< tester_type > tester( new tester_type( 4, 4 ) ); boost::lockfree::stack< long > q( 128 ); tester->run( q ); diff --git a/test/test_common.hpp b/test/test_common.hpp index a6029bab..24491a90 100644 --- a/test/test_common.hpp +++ b/test/test_common.hpp @@ -5,19 +5,19 @@ // http://www.boost.org/LICENSE_1_0.txt) #include "test_helpers.hpp" +#include +#include #include #include +#ifdef __VXWORKS__ +# include +#endif -#include #include -#include +#include namespace impl { -using boost::array; -using namespace boost; -using namespace std; - template < bool Bounded = false > struct queue_stress_tester { @@ -30,13 +30,13 @@ struct queue_stress_tester const int reader_threads; const int writer_threads; - boost::lockfree::detail::atomic< int > writers_finished; + std::atomic< int > writers_finished; - static_hashed_set< long, buckets > data; - static_hashed_set< long, buckets > dequeued; - array< std::set< long >, buckets > returned; + static_hashed_set< long, buckets > data; + static_hashed_set< long, buckets > dequeued; + std::array< std::set< long >, buckets > returned; - boost::lockfree::detail::atomic< int > push_count, pop_count; + std::atomic< int > push_count, pop_count; queue_stress_tester( int reader, int writer ) : reader_threads( reader ), @@ -58,13 +58,13 @@ struct queue_stress_tester if ( Bounded ) while ( stk.bounded_push( id ) == false ) { #ifdef __VXWORKS__ - thread::yield(); + std::this_thread::yield(); #endif } else while ( stk.push( id ) == false ) { #ifdef __VXWORKS__ - thread::yield(); + std::this_thread::yield(); #endif } ++push_count; @@ -72,7 +72,7 @@ struct queue_stress_tester writers_finished += 1; } - boost::lockfree::detail::atomic< bool > running; + std::atomic< bool > running; template < typename queue > bool consume_element( queue& q ) @@ -105,7 +105,7 @@ struct queue_stress_tester break; #ifdef __VXWORKS__ - thread::yield(); + std::this_thread::yield(); #endif } @@ -119,20 +119,20 @@ struct queue_stress_tester BOOST_WARN( stk.is_lock_free() ); writers_finished.store( 0 ); - thread_group writer; - thread_group reader; + boost::thread_group writer; + boost::thread_group reader; BOOST_TEST_REQUIRE( stk.empty() ); for ( int i = 0; i != reader_threads; ++i ) - reader.create_thread( boost::bind( &queue_stress_tester::template get_items< queue >, - this, - boost::ref( stk ) ) ); + reader.create_thread( [ & ] { + get_items( stk ); + } ); for ( int i = 0; i != writer_threads; ++i ) - writer.create_thread( boost::bind( &queue_stress_tester::template add_items< queue >, - this, - boost::ref( stk ) ) ); + writer.create_thread( [ & ] { + add_items( stk ); + } ); std::cout << "threads created" << std::endl; diff --git a/test/test_helpers.hpp b/test/test_helpers.hpp index e7a9fe24..b05d7529 100644 --- a/test/test_helpers.hpp +++ b/test/test_helpers.hpp @@ -7,18 +7,17 @@ #ifndef BOOST_LOCKFREE_TEST_HELPERS #define BOOST_LOCKFREE_TEST_HELPERS -#include -#include -#include #include -#include -#include +#include +#include +#include +#include template < typename int_type > int_type generate_id( void ) { - static boost::lockfree::detail::atomic< int_type > generator( 0 ); + static std::atomic< int_type > generator( 0 ); return ++generator; } @@ -38,10 +37,9 @@ class static_hashed_set { std::size_t index = calc_index( id ); - boost::lock_guard< boost::mutex > lock( ref_mutex[ index ] ); + std::lock_guard< std::mutex > lock( ref_mutex[ index ] ); - std::pair< typename std::set< int_type >::iterator, bool > p; - p = data[ index ].insert( id ); + auto p = data[ index ].insert( id ); return p.second; } @@ -50,7 +48,7 @@ class static_hashed_set { std::size_t index = calc_index( id ); - boost::lock_guard< boost::mutex > lock( ref_mutex[ index ] ); + std::lock_guard< std::mutex > lock( ref_mutex[ index ] ); return data[ index ].find( id ) != data[ index ].end(); } @@ -59,7 +57,7 @@ class static_hashed_set { std::size_t index = calc_index( id ); - boost::lock_guard< boost::mutex > lock( ref_mutex[ index ] ); + std::lock_guard< std::mutex > lock( ref_mutex[ index ] ); if ( data[ index ].find( id ) != data[ index ].end() ) { data[ index ].erase( id ); @@ -73,15 +71,15 @@ class static_hashed_set { std::size_t ret = 0; for ( int i = 0; i != buckets; ++i ) { - boost::lock_guard< boost::mutex > lock( ref_mutex[ i ] ); + std::lock_guard< std::mutex > lock( ref_mutex[ i ] ); ret += data[ i ].size(); } return ret; } private: - boost::array< std::set< int_type >, buckets > data; - mutable boost::array< boost::mutex, buckets > ref_mutex; + std::array< std::set< int_type >, buckets > data; + mutable std::array< std::mutex, buckets > ref_mutex; }; struct test_equal