From 885ccc7ff368fa36cec0066503b272c2f44d7d40 Mon Sep 17 00:00:00 2001 From: Alejandro Date: Sun, 27 Mar 2016 19:52:36 -0400 Subject: [PATCH 1/4] Added support for forwarding references in push() to allow for move construction and emplacement --- include/boost/lockfree/spsc_queue.hpp | 33 ++++++++++++++++----------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/include/boost/lockfree/spsc_queue.hpp b/include/boost/lockfree/spsc_queue.hpp index 5ecfb2a..e64a5de 100644 --- a/include/boost/lockfree/spsc_queue.hpp +++ b/include/boost/lockfree/spsc_queue.hpp @@ -98,7 +98,8 @@ class ringbuffer_base return write_available(write_index, read_index, max_size); } - bool push(T const & t, T * buffer, size_t max_size) + template + bool push(T * buffer, size_t max_size, Args&&... args) { 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); @@ -106,7 +107,7 @@ class ringbuffer_base if (next == read_index_.load(memory_order_acquire)) return false; /* ringbuffer is full */ - new (buffer + write_index) T(t); // copy-construct + new (buffer + write_index) T(std::forward(args)...); // construct write_index_.store(next, memory_order_release); @@ -445,9 +446,11 @@ class compile_time_sized_ringbuffer: } public: - bool push(T const & t) + + template + bool push(Args&&... args) { - return ringbuffer_base::push(t, data(), max_size); + return ringbuffer_base::push( data(), max_size, std::forward(args)...); } template @@ -558,9 +561,10 @@ class runtime_sized_ringbuffer: Alloc::deallocate(array_, max_elements_); } - bool push(T const & t) + template + bool push(Args&&... args) { - return ringbuffer_base::push(t, &*array_, max_elements_); + return ringbuffer_base::push( &*array_, max_elements_, std::forward(args)...); } template @@ -601,28 +605,28 @@ class runtime_sized_ringbuffer: template ConstIterator push(ConstIterator begin, ConstIterator end) { - return ringbuffer_base::push(begin, end, &*array_, max_elements_); + return ringbuffer_base::push(begin, end, array_, max_elements_); } size_type pop(T * ret, size_type size) { - return ringbuffer_base::pop(ret, size, &*array_, max_elements_); + return ringbuffer_base::pop(ret, size, array_, max_elements_); } template size_type pop_to_output_iterator(OutputIterator it) { - return ringbuffer_base::pop_to_output_iterator(it, &*array_, max_elements_); + return ringbuffer_base::pop_to_output_iterator(it, array_, max_elements_); } const T& front(void) const { - return ringbuffer_base::front(&*array_); + return ringbuffer_base::front(array_); } T& front(void) { - return ringbuffer_base::front(&*array_); + return ringbuffer_base::front(array_); } }; @@ -756,9 +760,12 @@ class spsc_queue: * * \note Thread-safe and wait-free * */ - bool push(T const & t) + + template + typename std::enable_if< std::is_constructible::value, bool>::type + push(Args&&... args) { - return base_type::push(t); + return base_type::push(std::forward(args)...); } /** Pops one object from ringbuffer. From 5aa79139f4e6df5e9d339b82916bc5282854eb19 Mon Sep 17 00:00:00 2001 From: Alejandro Date: Sun, 27 Mar 2016 20:02:48 -0400 Subject: [PATCH 2/4] Added support for forwarding references in push() to allow for move construction and emplacement --- include/boost/lockfree/spsc_queue.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/boost/lockfree/spsc_queue.hpp b/include/boost/lockfree/spsc_queue.hpp index e64a5de..bf970cc 100644 --- a/include/boost/lockfree/spsc_queue.hpp +++ b/include/boost/lockfree/spsc_queue.hpp @@ -605,28 +605,28 @@ class runtime_sized_ringbuffer: template ConstIterator push(ConstIterator begin, ConstIterator end) { - return ringbuffer_base::push(begin, end, array_, max_elements_); + return ringbuffer_base::push(begin, end, &*array_, max_elements_); } size_type pop(T * ret, size_type size) { - return ringbuffer_base::pop(ret, size, array_, max_elements_); + return ringbuffer_base::pop(ret, size, &*array_, max_elements_); } template size_type pop_to_output_iterator(OutputIterator it) { - return ringbuffer_base::pop_to_output_iterator(it, array_, max_elements_); + return ringbuffer_base::pop_to_output_iterator(it, &*array_, max_elements_); } const T& front(void) const { - return ringbuffer_base::front(array_); + return ringbuffer_base::front(&*array_); } T& front(void) { - return ringbuffer_base::front(array_); + return ringbuffer_base::front(&*array_); } }; From 77dfc81c50faaa9d41b874bacd66b78beb2c79f9 Mon Sep 17 00:00:00 2001 From: Alejandro Date: Sun, 27 Mar 2016 20:16:26 -0400 Subject: [PATCH 3/4] changed std:: specific constructs to boost:: --- include/boost/lockfree/spsc_queue.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/boost/lockfree/spsc_queue.hpp b/include/boost/lockfree/spsc_queue.hpp index bf970cc..80b8924 100644 --- a/include/boost/lockfree/spsc_queue.hpp +++ b/include/boost/lockfree/spsc_queue.hpp @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -762,7 +763,7 @@ class spsc_queue: * */ template - typename std::enable_if< std::is_constructible::value, bool>::type + typename boost::enable_if< typename boost::is_constructible::type, bool>::type push(Args&&... args) { return base_type::push(std::forward(args)...); From 62d20849c1b22b39205e089c099f67e9bb1b92a9 Mon Sep 17 00:00:00 2001 From: Alejandro Date: Sat, 9 Apr 2016 19:26:43 -0400 Subject: [PATCH 4/4] Added BOOST_HAS_RVALUE_REFS to check for r-value reference compliance --- include/boost/lockfree/spsc_queue.hpp | 117 +++++++++++++++++++++++--- 1 file changed, 107 insertions(+), 10 deletions(-) diff --git a/include/boost/lockfree/spsc_queue.hpp b/include/boost/lockfree/spsc_queue.hpp index 80b8924..ad507ef 100644 --- a/include/boost/lockfree/spsc_queue.hpp +++ b/include/boost/lockfree/spsc_queue.hpp @@ -18,7 +18,7 @@ #include #include #include -#include // for BOOST_LIKELY +#include // for BOOST_LIKELY and BOOST_HAS_RVALUE_REFS #include #include @@ -99,8 +99,7 @@ class ringbuffer_base return write_available(write_index, read_index, max_size); } - template - bool push(T * buffer, size_t max_size, Args&&... args) + bool 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); @@ -108,12 +107,48 @@ class ringbuffer_base if (next == read_index_.load(memory_order_acquire)) return false; /* ringbuffer is full */ - new (buffer + write_index) T(std::forward(args)...); // construct + new (buffer + write_index) T(t); // copy-construct write_index_.store(next, memory_order_release); return true; } +#ifdef BOOST_HAS_RVALUE_REFS + + 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 boost::enable_if< typename boost::is_constructible::type, bool>::type + emplace(T * buffer, size_t max_size, Args&&... args ) + { + 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::forward(args)...); // emplace + + write_index_.store(next, memory_order_release); + + return true; + } + +#endif size_t push(const T * input_buffer, size_t input_count, T * internal_buffer, size_t max_size) { @@ -447,13 +482,27 @@ class compile_time_sized_ringbuffer: } public: + bool push(T const & t) + { + return ringbuffer_base::push(t, data(), max_size); + } + +#ifdef BOOST_HAS_RVALUE_REFS + bool push(T&& t) + { + return ringbuffer_base::push(std::move(t), data(), max_size); + } + template - bool push(Args&&... args) + typename boost::enable_if< typename boost::is_constructible::type, bool>::type + emplace(Args&&... args) { - return ringbuffer_base::push( data(), max_size, std::forward(args)...); + return ringbuffer_base::emplace(data(), max_size, std::forward(args)...); } +#endif + template bool consume_one(Functor & f) { @@ -562,12 +611,28 @@ class runtime_sized_ringbuffer: Alloc::deallocate(array_, max_elements_); } + bool push(T const & t) + { + return ringbuffer_base::push(t, &*array_, max_elements_); + } +#ifdef BOOST_HAS_RVALUE_REFS + + bool push(T&& t) + { + return ringbuffer_base::push(std::move(t), &*array_, max_elements_); + } + + + template - bool push(Args&&... args) + typename boost::enable_if< typename boost::is_constructible::type, bool>::type + emplace(Args&&... args) { - return ringbuffer_base::push( &*array_, max_elements_, std::forward(args)...); + return ringbuffer_base::emplace(&*array_, max_elements_, std::forward(args)...); } +#endif + template bool consume_one(Functor & f) { @@ -761,14 +826,46 @@ class spsc_queue: * * \note Thread-safe and wait-free * */ + bool push(T const & t) + { + return base_type::push(t); + } + + +#ifdef BOOST_HAS_RVALUE_REFS + + /** Pushes object t to the ringbuffer via move construction/ + * + * \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)); + } + + /** Emplaces an instance of T to the ringbuffer via direct initialization using the given constructor arguments + * + * \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 + * */ template typename boost::enable_if< typename boost::is_constructible::type, bool>::type - push(Args&&... args) + emplace(Args&&... args) { - return base_type::push(std::forward(args)...); + return base_type::emplace(std::forward(args)...); } +#endif + /** Pops one object from ringbuffer. * * \pre only one thread is allowed to pop data to the spsc_queue