diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 71a67dd..2950f6b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -151,8 +151,11 @@ jobs: if: env.B2_USE_CCACHE with: path: ~/.ccache - key: ${{matrix.os}}-${{matrix.container}}-${{matrix.compiler}}-${{github.sha}} - restore-keys: ${{matrix.os}}-${{matrix.container}}-${{matrix.compiler}}- + key: ccache-${{matrix.os}}-${{matrix.compiler}}-${{ hashFiles('**/*.cpp', '**/*.hpp', '**/*.c', '**/*.h') }} + restore-keys: | + ccache-${{matrix.os}}-${{matrix.compiler}}- + ccache-${{matrix.os}}- + ccache- - name: Install packages if: matrix.install @@ -239,7 +242,7 @@ jobs: os: windows-2022 supported: true - toolset: clang-win - cxxstd: "14,17,20,latest" + cxxstd: "latest,20,17,14" addrmd: 32,64 os: windows-2022 supported: true @@ -353,6 +356,9 @@ jobs: git submodule update --init tools/boostdep python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY + # HACK: boost.functional seems to be missing? + git submodule update --init libs/functional + - name: Use library with add_subdirectory run: | cd ../boost-root/libs/$LIBRARY/test/cmake_subdir_test @@ -409,6 +415,8 @@ jobs: git submodule update --init tools/boostdep python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY + git submodule update --init libs/functional + - name: Configure run: | cd ../boost-root @@ -475,6 +483,8 @@ jobs: git submodule update --init tools/boostdep python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY + git submodule update --init libs/functional + - name: Configure run: | cd ../boost-root @@ -527,6 +537,8 @@ jobs: git submodule update --init tools/boostdep python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" %LIBRARY% + git submodule update --init libs/functional + - name: Use library with add_subdirectory (Debug) shell: cmd run: | @@ -580,6 +592,8 @@ jobs: git submodule update --init tools/boostdep python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" %LIBRARY% + git submodule update --init libs/functional + - name: Configure shell: cmd run: | @@ -651,6 +665,8 @@ jobs: git submodule update --init tools/boostdep python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" %LIBRARY% + git submodule update --init libs/functional + - name: Configure shell: cmd run: | diff --git a/include/boost/lockfree/detail/freelist.hpp b/include/boost/lockfree/detail/freelist.hpp index 1b49c3f..23776b7 100644 --- a/include/boost/lockfree/detail/freelist.hpp +++ b/include/boost/lockfree/detail/freelist.hpp @@ -39,7 +39,7 @@ namespace boost { namespace lockfree { namespace detail { template < typename T, typename Alloc = std::allocator< T > > class alignas( cacheline_bytes ) freelist_stack : Alloc { - struct freelist_node + struct BOOST_MAY_ALIAS freelist_node { tagged_ptr< freelist_node > next; }; @@ -395,7 +395,7 @@ struct runtime_sized_freelist_storage : boost::alignment::aligned_allocator_adap template < typename T, typename NodeStorage = runtime_sized_freelist_storage< T > > class fixed_size_freelist : NodeStorage { - struct freelist_node + struct BOOST_MAY_ALIAS freelist_node { tagged_index next; }; diff --git a/include/boost/lockfree/queue.hpp b/include/boost/lockfree/queue.hpp index 9be5fb6..9609ebe 100644 --- a/include/boost/lockfree/queue.hpp +++ b/include/boost/lockfree/queue.hpp @@ -104,7 +104,7 @@ class queue static constexpr bool node_based = !( has_capacity || fixed_sized ); static constexpr bool compile_time_sized = has_capacity; - struct alignas( detail::cacheline_bytes ) node + struct BOOST_MAY_ALIAS node { typedef typename detail::select_tagged_handle< node, node_based >::tagged_handle_type tagged_node_handle; typedef typename detail::select_tagged_handle< node, node_based >::handle_type handle_type; @@ -125,8 +125,8 @@ class queue node( void ) {} - atomic< tagged_node_handle > next; - T data; + alignas( detail::cacheline_bytes ) atomic< tagged_node_handle > next; + T data; }; typedef detail::extract_allocator_t< bound_args, node > node_allocator; @@ -177,8 +177,6 @@ class queue requires( has_capacity ) #endif : - head_( tagged_node_handle( 0, 0 ) ), - tail_( tagged_node_handle( 0, 0 ) ), pool( node_allocator(), capacity ) { // Don't use BOOST_STATIC_ASSERT() here since it will be evaluated when compiling @@ -191,10 +189,13 @@ class queue * * \pre Must specify a capacity<> argument * */ +#if !defined( BOOST_NO_CXX20_HDR_CONCEPTS ) + template < typename U > + requires( has_capacity ) +#else template < typename U, typename Enabler = std::enable_if< has_capacity > > +#endif 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 ) { initialize(); @@ -204,10 +205,14 @@ class queue * * \pre Must specify a capacity<> argument * */ +#if !defined( BOOST_NO_CXX20_HDR_CONCEPTS ) + explicit queue( allocator const& alloc ) + requires( has_capacity ) + : +#else 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 ) ), +#endif pool( alloc, capacity ) { initialize(); @@ -219,10 +224,14 @@ class queue * * \pre Must \b not specify a capacity<> argument * */ +#if !defined( BOOST_NO_CXX20_HDR_CONCEPTS ) + explicit queue( size_type n ) + requires( !has_capacity ) + : +#else 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 ) ), +#endif pool( node_allocator(), n + 1 ) { initialize(); @@ -234,10 +243,13 @@ class queue * * \pre Must \b not specify a capacity<> argument * */ +#if !defined( BOOST_NO_CXX20_HDR_CONCEPTS ) + template < typename U > + requires( !has_capacity ) +#else template < typename U, typename Enabler = std::enable_if< !has_capacity > > +#endif 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 ) { initialize(); @@ -249,10 +261,14 @@ class queue * * \pre Must \b not specify a capacity<> argument * */ +#if !defined( BOOST_NO_CXX20_HDR_CONCEPTS ) + queue( size_type n, allocator const& alloc ) + requires( !has_capacity ) + : +#else 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 ) ), +#endif pool( alloc, n + 1 ) { initialize(); @@ -625,8 +641,12 @@ class queue private: #ifndef BOOST_DOXYGEN_INVOKED - atomic< tagged_node_handle > head_; - alignas( detail::cacheline_bytes ) atomic< tagged_node_handle > tail_; + atomic< tagged_node_handle > head_ { + tagged_node_handle( 0, 0 ), + }; + alignas( detail::cacheline_bytes ) atomic< tagged_node_handle > tail_ { + tagged_node_handle( 0, 0 ), + }; pool_t pool; #endif diff --git a/include/boost/lockfree/spsc_queue.hpp b/include/boost/lockfree/spsc_queue.hpp index b2a4fcc..2205026 100644 --- a/include/boost/lockfree/spsc_queue.hpp +++ b/include/boost/lockfree/spsc_queue.hpp @@ -43,13 +43,11 @@ class ringbuffer_base #ifndef BOOST_DOXYGEN_INVOKED protected: typedef std::size_t size_t; - alignas( cacheline_bytes ) atomic< size_t > write_index_; - alignas( cacheline_bytes ) atomic< size_t > read_index_; + alignas( cacheline_bytes ) atomic< size_t > write_index_ {}; + alignas( cacheline_bytes ) atomic< size_t > read_index_ {}; protected: - ringbuffer_base( void ) : - write_index_( 0 ), - read_index_( 0 ) + ringbuffer_base( void ) {} static size_t next_index( size_t arg, size_t max_size ) @@ -653,7 +651,12 @@ class spsc_queue : public detail::make_ringbuffer< T, Options... >::ringbuffer_t * * \note This is just for API compatibility: an allocator isn't actually needed */ +#if !defined( BOOST_NO_CXX20_HDR_CONCEPTS ) + template < typename U > + requires( !runtime_sized ) +#else template < typename U, typename Enabler = std::enable_if< !runtime_sized > > +#endif explicit spsc_queue( typename boost::allocator_rebind< allocator, U >::type const& ) {} @@ -663,16 +666,27 @@ class spsc_queue : public detail::make_ringbuffer< T, Options... >::ringbuffer_t * * \note This is just for API compatibility: an allocator isn't actually needed */ +#if !defined( BOOST_NO_CXX20_HDR_CONCEPTS ) + explicit spsc_queue( allocator const& ) + requires( !runtime_sized ) +#else template < typename Enabler = std::enable_if< !runtime_sized > > explicit spsc_queue( allocator const& ) +#endif {} /** Constructs a spsc_queue for element_count elements * * \pre spsc_queue must be configured to be sized at run-time */ +#if !defined( BOOST_NO_CXX20_HDR_CONCEPTS ) + explicit spsc_queue( size_type element_count ) + requires( runtime_sized ) +#else template < typename Enabler = std::enable_if< runtime_sized > > - explicit spsc_queue( size_type element_count ) : + explicit spsc_queue( size_type element_count ) +#endif + : base_type( element_count ) {} @@ -680,7 +694,12 @@ class spsc_queue : public detail::make_ringbuffer< T, Options... >::ringbuffer_t * * \pre spsc_queue must be configured to be sized at run-time */ +#if !defined( BOOST_NO_CXX20_HDR_CONCEPTS ) + template < typename U > + requires( runtime_sized ) +#else template < typename U, typename Enabler = std::enable_if< runtime_sized > > +#endif spsc_queue( size_type element_count, typename boost::allocator_rebind< allocator, U >::type const& alloc ) : base_type( alloc, element_count ) {} @@ -689,8 +708,14 @@ class spsc_queue : public detail::make_ringbuffer< T, Options... >::ringbuffer_t * * \pre spsc_queue must be configured to be sized at run-time */ +#if !defined( BOOST_NO_CXX20_HDR_CONCEPTS ) + spsc_queue( size_type element_count, allocator_arg const& alloc ) + requires( runtime_sized ) +#else template < typename Enabler = std::enable_if< runtime_sized > > - spsc_queue( size_type element_count, allocator_arg const& alloc ) : + spsc_queue( size_type element_count, allocator_arg const& alloc ) +#endif + : base_type( alloc, element_count ) {} @@ -739,7 +764,12 @@ class spsc_queue : public detail::make_ringbuffer< T, Options... >::ringbuffer_t * * \note Thread-safe and wait-free */ +#if !defined( BOOST_NO_CXX20_HDR_CONCEPTS ) + template < typename U > + requires( std::is_convertible_v< T, U > ) +#else template < typename U, typename Enabler = std::enable_if< std::is_convertible< T, U >::value > > +#endif bool pop( U& ret ) { return consume_one( [ & ]( T&& t ) { @@ -866,8 +896,16 @@ class spsc_queue : public detail::make_ringbuffer< T, Options... >::ringbuffer_t * * \note Thread-safe and wait-free * */ +#if !defined( BOOST_NO_CXX20_HDR_CONCEPTS ) template < typename OutputIterator > - typename std::enable_if< !std::is_convertible< T, OutputIterator >::value, size_type >::type pop( OutputIterator it ) + requires( !std::is_convertible_v< T, OutputIterator > ) + size_type +#else + template < typename OutputIterator, + typename Enabler = std::enable_if< !std::is_convertible< T, OutputIterator >::value > > + typename std::enable_if< !std::is_convertible< T, OutputIterator >::value, size_type >::type +#endif + pop( OutputIterator it ) { return base_type::pop_to_output_iterator( it ); } diff --git a/include/boost/lockfree/stack.hpp b/include/boost/lockfree/stack.hpp index b92ed61..d5696d5 100644 --- a/include/boost/lockfree/stack.hpp +++ b/include/boost/lockfree/stack.hpp @@ -82,7 +82,7 @@ class stack static const bool node_based = !( has_capacity || fixed_sized ); static const bool compile_time_sized = has_capacity; - struct node + struct BOOST_MAY_ALIAS node { node( const T& val ) : v( val ) @@ -155,7 +155,12 @@ class stack * * \pre Must specify a capacity<> argument * */ +#if !defined( BOOST_NO_CXX20_HDR_CONCEPTS ) + template < typename U > + requires( has_capacity ) +#else template < typename U, typename Enabler = std::enable_if< has_capacity > > +#endif explicit stack( typename boost::allocator_rebind< node_allocator, U >::type const& alloc ) : pool( alloc, capacity ) { @@ -166,8 +171,14 @@ class stack * * \pre Must specify a capacity<> argument * */ +#if !defined( BOOST_NO_CXX20_HDR_CONCEPTS ) + explicit stack( allocator const& alloc ) + requires( has_capacity ) + : +#else template < typename Enabler = std::enable_if< has_capacity > > explicit stack( allocator const& alloc ) : +#endif pool( alloc, capacity ) { initialize(); @@ -179,8 +190,14 @@ class stack * * \pre Must \b not specify a capacity<> argument * */ +#if !defined( BOOST_NO_CXX20_HDR_CONCEPTS ) + explicit stack( size_type n ) + requires( !has_capacity ) + : +#else template < typename Enabler = std::enable_if< !has_capacity > > explicit stack( size_type n ) : +#endif pool( node_allocator(), n ) { initialize(); @@ -198,7 +215,12 @@ class stack * * \pre Must \b not specify a capacity<> argument * */ +#if !defined( BOOST_NO_CXX20_HDR_CONCEPTS ) + template < typename U > + requires( !has_capacity ) +#else template < typename U, typename Enabler = std::enable_if< !has_capacity > > +#endif stack( size_type n, typename boost::allocator_rebind< node_allocator, U >::type const& alloc ) : pool( alloc, n ) { @@ -211,8 +233,14 @@ class stack * * \pre Must \b not specify a capacity<> argument * */ +#if !defined( BOOST_NO_CXX20_HDR_CONCEPTS ) + stack( size_type n, node_allocator const& alloc ) + requires( !has_capacity ) + : +#else template < typename Enabler = std::enable_if< !has_capacity > > stack( size_type n, node_allocator const& alloc ) : +#endif pool( alloc, n ) { initialize(); @@ -224,8 +252,13 @@ class stack * \note thread-safe, may block if memory allocator blocks * * */ +#if !defined( BOOST_NO_CXX20_HDR_CONCEPTS ) + void reserve( size_type n ) + requires( !has_capacity ) +#else template < typename Enabler = std::enable_if< !has_capacity > > void reserve( size_type n ) +#endif { pool.template reserve< true >( n ); } @@ -236,8 +269,13 @@ class stack * \note not thread-safe, may block if memory allocator blocks * * */ +#if !defined( BOOST_NO_CXX20_HDR_CONCEPTS ) + void reserve_unsafe( size_type n ) + requires( !has_capacity ) +#else template < typename Enabler = std::enable_if< !has_capacity > > void reserve_unsafe( size_type n ) +#endif { pool.template reserve< false >( n ); } @@ -547,7 +585,12 @@ class stack * \note Thread-safe and non-blocking * * */ +#if !defined( BOOST_NO_CXX20_HDR_CONCEPTS ) + template < typename U > + requires( std::is_convertible_v< T, U > ) +#else template < typename U, typename Enabler = std::enable_if< std::is_convertible< T, U >::value > > +#endif bool pop( U& ret ) { return consume_one( [ & ]( T&& arg ) { @@ -613,7 +656,12 @@ class stack * \note Not thread-safe, but non-blocking * * */ +#if !defined( BOOST_NO_CXX20_HDR_CONCEPTS ) + template < typename U > + requires( std::is_convertible_v< T, U > ) +#else template < typename U, typename Enabler = std::enable_if< std::is_convertible< T, U >::value > > +#endif bool unsynchronized_pop( U& ret ) { tagged_node_handle old_tos = tos.load( detail::memory_order_relaxed ); diff --git a/test/cmake_subdir_test/CMakeLists.txt b/test/cmake_subdir_test/CMakeLists.txt index d838496..7a4441a 100644 --- a/test/cmake_subdir_test/CMakeLists.txt +++ b/test/cmake_subdir_test/CMakeLists.txt @@ -10,25 +10,17 @@ add_subdirectory(../.. boostorg/lockfree) set(deps align - array assert atomic config core - integer - iterator - mpl parameter predef - tuple - type_traits utility # transitive bind - concept_check container_hash - conversion describe detail function @@ -36,13 +28,14 @@ set(deps functional fusion io - move mp11 + mpl optional preprocessor - smart_ptr - typeof throw_exception + tuple + type_traits + typeof winapi )