From 1e714940344f09523e6ab0faee86464b0eed0645 Mon Sep 17 00:00:00 2001 From: Thomas Novotny Date: Wed, 3 Aug 2016 00:50:07 +0200 Subject: [PATCH 01/10] minimal changes to allow single move values to be pushed and poped --- include/boost/lockfree/spsc_queue.hpp | 76 ++++++++++++++++++++++----- 1 file changed, 63 insertions(+), 13 deletions(-) diff --git a/include/boost/lockfree/spsc_queue.hpp b/include/boost/lockfree/spsc_queue.hpp index 5ecfb2a..c1ea4f8 100644 --- a/include/boost/lockfree/spsc_queue.hpp +++ b/include/boost/lockfree/spsc_queue.hpp @@ -98,7 +98,24 @@ class ringbuffer_base return write_available(write_index, read_index, max_size); } - bool push(T const & t, T * buffer, size_t max_size) + bool push( T && t, T * buffer, size_t max_size ) + { + const size_t write_index = write_index_.load( memory_order_relaxed ); // only written from push thread + const size_t next = next_index( write_index, max_size ); + + if( next == read_index_.load( memory_order_acquire ) ) + return false; /* ringbuffer is full */ + + new (buffer + write_index) T(std::move(t)); // move-construct + + write_index_.store( next, memory_order_release ); + + return true; + } + + template + typename std::enable_if< std::is_copy_constructible::value, bool >::type + push(T const & t, T * buffer, size_t max_size) { const size_t write_index = write_index_.load(memory_order_relaxed); // only written from push thread const size_t next = next_index(write_index, max_size); @@ -382,18 +399,23 @@ class ringbuffer_base return write_index == read_index; } - template< class OutputIterator > - OutputIterator copy_and_delete( T * first, T * last, OutputIterator out ) + template< class OutputIterator> + typename std::enable_if< boost::has_trivial_destructor::value, OutputIterator >::type + copy_and_delete( T * first, T * last, OutputIterator out ) { - if (boost::has_trivial_destructor::value) { - return std::copy(first, last, out); // will use memcpy if possible - } else { - for (; first != last; ++first, ++out) { - *out = *first; - first->~T(); - } - return out; + return std::copy(first, last, out); // will use memcpy if possible + } + + + template + typename std::enable_if< ! boost::has_trivial_destructor::value, OutputIterator >::type + copy_and_delete( T * first, T * last, OutputIterator out ) + { + for (; first != last; ++first, ++out) { + *out = std::move(*first); + first->~T(); } + return out; } template< class Functor > @@ -445,11 +467,18 @@ class compile_time_sized_ringbuffer: } public: + + template< typename = std::enable_if< std::is_copy_constructible::value, bool >::type > bool push(T const & t) { return ringbuffer_base::push(t, data(), max_size); } + bool push(T&& t) + { + return ringbuffer_base::push(std::move(t), data(), max_size); + } + template bool consume_one(Functor & f) { @@ -558,11 +587,18 @@ class runtime_sized_ringbuffer: Alloc::deallocate(array_, max_elements_); } - bool push(T const & t) + template< typename = std::enable_if< std::is_copy_constructible::value, bool >::type > + bool + push(T const & t) { return ringbuffer_base::push(t, &*array_, max_elements_); } + bool push(T&& t) + { + return ringbuffer_base::push(std::move(t), &*array_, max_elements_); + } + template bool consume_one(Functor & f) { @@ -756,11 +792,25 @@ class spsc_queue: * * \note Thread-safe and wait-free * */ - bool push(T const & t) + template< typename = std::enable_if< std::is_copy_constructible::value, bool >::type > + bool push(T const & t) { return base_type::push(t); } + /** Pushes object t to the ringbuffer. + * + * \pre only one thread is allowed to push data to the spsc_queue + * \post object will be pushed to the spsc_queue, unless it is full. + * \return true, if the push operation is successful. + * + * \note Thread-safe and wait-free + * */ + bool push( T && t ) + { + return base_type::push( std::move( t ) ); + } + /** Pops one object from ringbuffer. * * \pre only one thread is allowed to pop data to the spsc_queue From 2329d4755d52094463d9cf12c3de4edf6f5a7677 Mon Sep 17 00:00:00 2001 From: Thomas Novotny Date: Sun, 23 Jul 2017 13:21:22 +0200 Subject: [PATCH 02/10] fixed compile issues for pop on spsc_queue> --- .../boost/lockfree/detail/move_payload.hpp | 75 +++++++++++++++++++ include/boost/lockfree/spsc_queue.hpp | 24 ++++-- 2 files changed, 94 insertions(+), 5 deletions(-) create mode 100644 include/boost/lockfree/detail/move_payload.hpp diff --git a/include/boost/lockfree/detail/move_payload.hpp b/include/boost/lockfree/detail/move_payload.hpp new file mode 100644 index 0000000..45a8ec2 --- /dev/null +++ b/include/boost/lockfree/detail/move_payload.hpp @@ -0,0 +1,75 @@ +// boost lockfree: move_payload helper +// +// Copyright (C) 2011 Tim Blechmann +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_LOCKFREE_DETAIL_MOVE_PAYLOAD_HPP_INCLUDED +#define BOOST_LOCKFREE_DETAIL_MOVE_PAYLOAD_HPP_INCLUDED + +#include +#include + +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable: 4512) // assignment operator could not be generated +#endif + +namespace boost { +namespace lockfree { +namespace detail { + +struct move_convertible +{ + template + static void move(T & t, U & u) + { + u = std::move(t); + } +}; + +struct move_constructible_and_assignable +{ + template + static void ^move(T & t, U & u) + { + u = U(std::move(t)); + } +}; + +template +void move_payload(T & t, U & u) +{ + typedef typename boost::mpl::if_::type, + move_convertible, + move_constructible_and_assignable + >::type move_type; + move_type::move(t, u); +} + +template +struct consume_via_move +{ + consume_via_move(T & out): + out_(std::move(out)) + {} + + template + void operator()(U & element) + { + move_payload(element, out_); + } + + T & out_; +}; + + +}}} + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +#endif /* BOOST_LOCKFREE_DETAIL_COPY_PAYLOAD_HPP_INCLUDED */ diff --git a/include/boost/lockfree/spsc_queue.hpp b/include/boost/lockfree/spsc_queue.hpp index c1ea4f8..5e1ade2 100644 --- a/include/boost/lockfree/spsc_queue.hpp +++ b/include/boost/lockfree/spsc_queue.hpp @@ -12,19 +12,21 @@ #include #include +#include #include #include +#include // for BOOST_LIKELY #include #include #include -#include // for BOOST_LIKELY #include #include #include #include +#include #include #include @@ -825,22 +827,34 @@ class spsc_queue: return consume_one( consume_functor ); } - /** Pops one object from ringbuffer. + /** Pops one object from ringbuffer. If it is move assignable it will be moved, + * otherwise it will be copied. * * \pre only one thread is allowed to pop data to the spsc_queue - * \post if ringbuffer is not empty, object will be copied to ret. + * \post if ringbuffer is not empty, object will be assigned to ret. * \return true, if the pop operation is successful, false if ringbuffer was empty. * * \note Thread-safe and wait-free */ template - typename boost::enable_if::type, bool>::type - pop (U & ret) + typename boost::enable_if::value && !std::is_move_assignable::value>::type, bool>::type + pop ( U & ret) { detail::consume_via_copy consume_functor(ret); return consume_one( consume_functor ); } + template + typename boost::enable_if::value && std::is_move_assignable::value>::type, bool>::type + pop ( U & ret ) + { + detail::consume_via_move consume_functor( ret ); + return consume_one( consume_functor ); + } + + /** Pushes as many objects from the array t as there is space. * * \pre only one thread is allowed to push data to the spsc_queue From 5e214c2173455790b2468544103756750984d3c7 Mon Sep 17 00:00:00 2001 From: Thomas Novotny Date: Sun, 23 Jul 2017 14:26:35 +0200 Subject: [PATCH 03/10] added test case for spsc_queue> --- test/spsc_queue_test.cpp | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/test/spsc_queue_test.cpp b/test/spsc_queue_test.cpp index 99f393f..b6bb87a 100644 --- a/test/spsc_queue_test.cpp +++ b/test/spsc_queue_test.cpp @@ -16,8 +16,8 @@ #include #include -#include "test_helpers.hpp" #include "test_common.hpp" +#include "test_helpers.hpp" using namespace boost; using namespace boost::lockfree; @@ -405,3 +405,31 @@ BOOST_AUTO_TEST_CASE( spsc_queue_reset_test ) BOOST_REQUIRE(f.empty()); } + + +BOOST_AUTO_TEST_CASE( spsc_queue_unique_ptr_push_pop_test ) +{ + spsc_queue, capacity<64> > f; + + BOOST_REQUIRE(f.empty()); + + unique_ptr in; + unique_ptr out; + + const int fortytwo = 42; + + in.reset( new int[1] ); + in[0] = fortytwo; + int* data = in.get(); + + BOOST_REQUIRE( f.push( std::move(in) ) ); + BOOST_REQUIRE( f.pop(out) ); + + BOOST_REQUIRE( out.get() == data ); + BOOST_REQUIRE( out[0] == fortytwo ); + + f.reset(); + + BOOST_REQUIRE(f.empty()); +} + From 75dd3946e615b9190b03dcbf4b7dbd9e11e914df Mon Sep 17 00:00:00 2001 From: Thomas Novotny Date: Sun, 23 Jul 2017 14:30:09 +0200 Subject: [PATCH 04/10] fixed errors in move_payload that caused compile errors --- include/boost/lockfree/detail/move_payload.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/lockfree/detail/move_payload.hpp b/include/boost/lockfree/detail/move_payload.hpp index 45a8ec2..2196a84 100644 --- a/include/boost/lockfree/detail/move_payload.hpp +++ b/include/boost/lockfree/detail/move_payload.hpp @@ -33,7 +33,7 @@ struct move_convertible struct move_constructible_and_assignable { template - static void ^move(T & t, U & u) + static void move(T & t, U & u) { u = U(std::move(t)); } @@ -53,7 +53,7 @@ template struct consume_via_move { consume_via_move(T & out): - out_(std::move(out)) + out_(out) {} template From 9137efc3fce7ee8cf7982fdda6b0cb4881847cd2 Mon Sep 17 00:00:00 2001 From: Thomas Novotny Date: Fri, 29 Dec 2017 23:37:53 +0100 Subject: [PATCH 05/10] try to make code C++98/C++03 compatible use BOOST_NO_CXX11_RVALUE_REFERENCES to hide functions that take rvalue references add detail::is_move_assignable as the boost type_traits don't seem to have one switch from std::enable_if to boost::enable_if and disable_if switch from std::move to boost::move --- include/boost/lockfree/spsc_queue.hpp | 75 ++++++++++++++++++--------- test/spsc_queue_test.cpp | 2 + 2 files changed, 52 insertions(+), 25 deletions(-) diff --git a/include/boost/lockfree/spsc_queue.hpp b/include/boost/lockfree/spsc_queue.hpp index 5e1ade2..dbc730a 100644 --- a/include/boost/lockfree/spsc_queue.hpp +++ b/include/boost/lockfree/spsc_queue.hpp @@ -23,10 +23,13 @@ #include #include +#include #include #include +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES #include +#endif #include #include @@ -38,6 +41,20 @@ namespace boost { namespace lockfree { namespace detail { + // there does not seem to be a coresponding boost trait, + // so for C++98, C++03 compatibility we roll our own falling back on std:: + template + struct is_move_assignable + { + static const bool value = +#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES + false; +#else + std::is_move_assignable::value; +#endif + }; + + typedef parameter::parameters, boost::parameter::optional > ringbuffer_signature; @@ -100,7 +117,8 @@ class ringbuffer_base return write_available(write_index, read_index, max_size); } - bool push( T && t, T * buffer, size_t max_size ) +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + bool push(T && t, T * buffer, size_t max_size ) { const size_t write_index = write_index_.load( memory_order_relaxed ); // only written from push thread const size_t next = next_index( write_index, max_size ); @@ -108,15 +126,16 @@ class ringbuffer_base if( next == read_index_.load( memory_order_acquire ) ) return false; /* ringbuffer is full */ - new (buffer + write_index) T(std::move(t)); // move-construct + new (buffer + write_index) T(boost::move(t)); // move-construct write_index_.store( next, memory_order_release ); return true; } +#endif template - typename std::enable_if< std::is_copy_constructible::value, bool >::type + typename boost::enable_if::value, bool >::type push(T const & t, T * buffer, size_t max_size) { const size_t write_index = write_index_.load(memory_order_relaxed); // only written from push thread @@ -401,8 +420,8 @@ class ringbuffer_base return write_index == read_index; } - template< class OutputIterator> - typename std::enable_if< boost::has_trivial_destructor::value, OutputIterator >::type + template + typename boost::enable_if::value, OutputIterator >::type copy_and_delete( T * first, T * last, OutputIterator out ) { return std::copy(first, last, out); // will use memcpy if possible @@ -410,17 +429,17 @@ class ringbuffer_base template - typename std::enable_if< ! boost::has_trivial_destructor::value, OutputIterator >::type + typename boost::disable_if::value, OutputIterator >::type copy_and_delete( T * first, T * last, OutputIterator out ) { for (; first != last; ++first, ++out) { - *out = std::move(*first); + *out = boost::move(*first); first->~T(); } return out; } - template< class Functor > + template void run_functor_and_delete( T * first, T * last, Functor & functor ) { for (; first != last; ++first) { @@ -470,16 +489,18 @@ class compile_time_sized_ringbuffer: public: - template< typename = std::enable_if< std::is_copy_constructible::value, bool >::type > + template< typename = boost::enable_if::value, bool >::type > bool push(T const & t) { return ringbuffer_base::push(t, data(), max_size); } - bool push(T&& t) +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + bool push(T && t) { - return ringbuffer_base::push(std::move(t), data(), max_size); + return ringbuffer_base::push(boost::move(t), data(), max_size); } +#endif template bool consume_one(Functor & f) @@ -589,17 +610,19 @@ class runtime_sized_ringbuffer: Alloc::deallocate(array_, max_elements_); } - template< typename = std::enable_if< std::is_copy_constructible::value, bool >::type > + template< typename = boost::enable_if::value, bool >::type > bool push(T const & t) { return ringbuffer_base::push(t, &*array_, max_elements_); } - bool push(T&& t) +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + bool push(T && t) { - return ringbuffer_base::push(std::move(t), &*array_, max_elements_); + return ringbuffer_base::push(boost::move(t), &*array_, max_elements_); } +#endif template bool consume_one(Functor & f) @@ -794,12 +817,13 @@ class spsc_queue: * * \note Thread-safe and wait-free * */ - template< typename = std::enable_if< std::is_copy_constructible::value, bool >::type > - bool push(T const & t) + template< typename = boost::enable_if::value, bool >::type > + bool push(T const & t) { return base_type::push(t); } +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES /** Pushes object t to the ringbuffer. * * \pre only one thread is allowed to push data to the spsc_queue @@ -808,10 +832,11 @@ class spsc_queue: * * \note Thread-safe and wait-free * */ - bool push( T && t ) + bool push(T && t) { - return base_type::push( std::move( t ) ); + return base_type::push(boost::move(t)); } +#endif /** Pops one object from ringbuffer. * @@ -824,7 +849,7 @@ class spsc_queue: bool pop () { detail::consume_noop consume_functor; - return consume_one( consume_functor ); + return consume_one(consume_functor); } /** Pops one object from ringbuffer. If it is move assignable it will be moved, @@ -838,20 +863,20 @@ class spsc_queue: */ template typename boost::enable_if::value && !std::is_move_assignable::value>::type, bool>::type - pop ( U & ret) + is_convertible::value && !detail::is_move_assignable::value>::type, bool>::type + pop(U & ret) { detail::consume_via_copy consume_functor(ret); - return consume_one( consume_functor ); + return consume_one(consume_functor); } template typename boost::enable_if::value && std::is_move_assignable::value>::type, bool>::type - pop ( U & ret ) + is_convertible::value && detail::is_move_assignable::value>::type, bool>::type + pop(U & ret) { detail::consume_via_move consume_functor( ret ); - return consume_one( consume_functor ); + return consume_one(consume_functor); } diff --git a/test/spsc_queue_test.cpp b/test/spsc_queue_test.cpp index b6bb87a..7c798d8 100644 --- a/test/spsc_queue_test.cpp +++ b/test/spsc_queue_test.cpp @@ -406,6 +406,7 @@ BOOST_AUTO_TEST_CASE( spsc_queue_reset_test ) BOOST_REQUIRE(f.empty()); } +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES BOOST_AUTO_TEST_CASE( spsc_queue_unique_ptr_push_pop_test ) { @@ -433,3 +434,4 @@ BOOST_AUTO_TEST_CASE( spsc_queue_unique_ptr_push_pop_test ) BOOST_REQUIRE(f.empty()); } +#endif From fd20ae5e5f5e877833de325dafdd435380d44383 Mon Sep 17 00:00:00 2001 From: Thomas Novotny Date: Fri, 29 Dec 2017 23:54:48 +0100 Subject: [PATCH 06/10] improve C++98/C++03 compatibility #include type_traits only if we need it --- include/boost/lockfree/spsc_queue.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/boost/lockfree/spsc_queue.hpp b/include/boost/lockfree/spsc_queue.hpp index dbc730a..1cee68e 100644 --- a/include/boost/lockfree/spsc_queue.hpp +++ b/include/boost/lockfree/spsc_queue.hpp @@ -12,7 +12,9 @@ #include #include -#include +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +#include // for is_move_assignable +#endif #include #include From e38736974b5d0fdb56f9074321e62aa18ed84ec3 Mon Sep 17 00:00:00 2001 From: Thomas Novotny Date: Sat, 30 Dec 2017 00:27:55 +0100 Subject: [PATCH 07/10] fixed compile error introduced by switching std to boost::enable_if --- include/boost/lockfree/spsc_queue.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/boost/lockfree/spsc_queue.hpp b/include/boost/lockfree/spsc_queue.hpp index 1cee68e..1f4d085 100644 --- a/include/boost/lockfree/spsc_queue.hpp +++ b/include/boost/lockfree/spsc_queue.hpp @@ -137,7 +137,7 @@ class ringbuffer_base #endif template - typename boost::enable_if::value, bool >::type + typename boost::enable_if, bool >::type push(T const & t, T * buffer, size_t max_size) { const size_t write_index = write_index_.load(memory_order_relaxed); // only written from push thread @@ -423,7 +423,7 @@ class ringbuffer_base } template - typename boost::enable_if::value, OutputIterator >::type + typename boost::enable_if, OutputIterator >::type copy_and_delete( T * first, T * last, OutputIterator out ) { return std::copy(first, last, out); // will use memcpy if possible @@ -431,7 +431,7 @@ class ringbuffer_base template - typename boost::disable_if::value, OutputIterator >::type + typename boost::disable_if, OutputIterator >::type copy_and_delete( T * first, T * last, OutputIterator out ) { for (; first != last; ++first, ++out) { From 8e74c852efe11b9cab53ee7d0429c0c5a59eefe2 Mon Sep 17 00:00:00 2001 From: Thomas Novotny Date: Sat, 30 Dec 2017 03:39:35 +0100 Subject: [PATCH 08/10] make it compile with C++98 the SFINAE had to be rewritten in a C++98 compatible way it now compiles when I use set(CMAKE_CXX_STANDARD 98) --- include/boost/lockfree/spsc_queue.hpp | 64 ++++++++++++++++----------- 1 file changed, 37 insertions(+), 27 deletions(-) diff --git a/include/boost/lockfree/spsc_queue.hpp b/include/boost/lockfree/spsc_queue.hpp index 1f4d085..5b20035 100644 --- a/include/boost/lockfree/spsc_queue.hpp +++ b/include/boost/lockfree/spsc_queue.hpp @@ -12,13 +12,16 @@ #include #include + +#include // for BOOST_LIKELY + #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES #include // for is_move_assignable #endif #include #include -#include // for BOOST_LIKELY + #include #include #include @@ -31,6 +34,7 @@ #include #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES #include +#include #endif #include #include @@ -136,9 +140,9 @@ class ringbuffer_base } #endif - template - typename boost::enable_if, bool >::type - push(T const & t, T * buffer, size_t max_size) + template + typename boost::enable_if::value && boost::is_same::value>, bool>::type + push(U const & t, U * buffer, size_t max_size) { const size_t write_index = write_index_.load(memory_order_relaxed); // only written from push thread const size_t next = next_index(write_index, max_size); @@ -422,20 +426,24 @@ class ringbuffer_base return write_index == read_index; } + template - typename boost::enable_if, OutputIterator >::type - copy_and_delete( T * first, T * last, OutputIterator out ) + typename boost::enable_if, OutputIterator>::type + copy_and_delete(T * first, T * last, OutputIterator out) { return std::copy(first, last, out); // will use memcpy if possible } - template - typename boost::disable_if, OutputIterator >::type - copy_and_delete( T * first, T * last, OutputIterator out ) + typename boost::disable_if, OutputIterator>::type + copy_and_delete(T * first, T * last, OutputIterator out) { for (; first != last; ++first, ++out) { +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES *out = boost::move(*first); +#else + *out = *first; +#endif first->~T(); } return out; @@ -491,8 +499,9 @@ class compile_time_sized_ringbuffer: public: - template< typename = boost::enable_if::value, bool >::type > - bool push(T const & t) + template + typename boost::enable_if::value && boost::is_same::value>,bool>::type + push(U const & t) { return ringbuffer_base::push(t, data(), max_size); } @@ -612,9 +621,9 @@ class runtime_sized_ringbuffer: Alloc::deallocate(array_, max_elements_); } - template< typename = boost::enable_if::value, bool >::type > - bool - push(T const & t) + template< typename U> + typename boost::enable_if< boost::integral_constant::value && boost::is_same::value>, bool >::type + push(U const & t) { return ringbuffer_base::push(t, &*array_, max_elements_); } @@ -819,10 +828,10 @@ class spsc_queue: * * \note Thread-safe and wait-free * */ - template< typename = boost::enable_if::value, bool >::type > - bool push(T const & t) + bool + push(T const & u) { - return base_type::push(t); + return base_type::push(u); } #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES @@ -863,24 +872,25 @@ class spsc_queue: * * \note Thread-safe and wait-free */ - template - typename boost::enable_if::value && !detail::is_move_assignable::value>::type, bool>::type - pop(U & ret) +#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES + + bool + pop(T & ret) { - detail::consume_via_copy consume_functor(ret); + detail::consume_via_copy consume_functor(ret); return consume_one(consume_functor); } - template - typename boost::enable_if::value && detail::is_move_assignable::value>::type, bool>::type - pop(U & ret) +#else + + bool + pop(T & ret) { - detail::consume_via_move consume_functor( ret ); + detail::consume_via_move consume_functor( ret ); return consume_one(consume_functor); } +#endif /** Pushes as many objects from the array t as there is space. * From 09e866d187df895b7b425e55b691ca682233e185 Mon Sep 17 00:00:00 2001 From: Thomas Novotny Date: Sat, 30 Dec 2017 04:10:44 +0100 Subject: [PATCH 09/10] make pop back function template the receiver was originally a convertible template paramter. this erroneously got changed while trying to get it to compile. --- include/boost/lockfree/spsc_queue.hpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/include/boost/lockfree/spsc_queue.hpp b/include/boost/lockfree/spsc_queue.hpp index 5b20035..54eaa8b 100644 --- a/include/boost/lockfree/spsc_queue.hpp +++ b/include/boost/lockfree/spsc_queue.hpp @@ -874,19 +874,21 @@ class spsc_queue: */ #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES - bool - pop(T & ret) + template + typename boost::enable_if::type, bool>::type + pop(U & ret) { - detail::consume_via_copy consume_functor(ret); + detail::consume_via_copy consume_functor(ret); return consume_one(consume_functor); } #else - bool - pop(T & ret) + template + typename boost::enable_if::type, bool>::type + pop(U & ret) { - detail::consume_via_move consume_functor( ret ); + detail::consume_via_move consume_functor( ret ); return consume_one(consume_functor); } From 9304d956fb9dc67b42a38efb797b57e4616a9aaf Mon Sep 17 00:00:00 2001 From: Thomas Novotny Date: Sat, 30 Dec 2017 23:50:03 +0100 Subject: [PATCH 10/10] remove detail::is_move_assignable as it is no longer needed --- include/boost/lockfree/spsc_queue.hpp | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/include/boost/lockfree/spsc_queue.hpp b/include/boost/lockfree/spsc_queue.hpp index 54eaa8b..e8c4a9f 100644 --- a/include/boost/lockfree/spsc_queue.hpp +++ b/include/boost/lockfree/spsc_queue.hpp @@ -13,11 +13,7 @@ #include #include -#include // for BOOST_LIKELY - -#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES -#include // for is_move_assignable -#endif +#include // for BOOST_NO_CXX11_ #include #include @@ -47,20 +43,6 @@ namespace boost { namespace lockfree { namespace detail { - // there does not seem to be a coresponding boost trait, - // so for C++98, C++03 compatibility we roll our own falling back on std:: - template - struct is_move_assignable - { - static const bool value = -#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES - false; -#else - std::is_move_assignable::value; -#endif - }; - - typedef parameter::parameters, boost::parameter::optional > ringbuffer_signature;