diff --git a/cds/container/weak_ringbuffer.h b/cds/container/weak_ringbuffer.h index 0c61bf3d3..24f5dcee0 100644 --- a/cds/container/weak_ringbuffer.h +++ b/cds/container/weak_ringbuffer.h @@ -196,7 +196,7 @@ namespace cds { namespace container { template bool push( Q* arr, size_t count, CopyFunc copy ) { - assert( count < capacity()); + assert( count <= capacity()); counter_type back = back_.load( memory_model::memory_order_relaxed ); assert( static_cast( back - pfront_ ) <= capacity()); @@ -352,10 +352,10 @@ namespace cds { namespace container { template bool pop( Q* arr, size_t count, CopyFunc copy ) { - assert( count < capacity()); + assert( count <= capacity()); counter_type front = front_.load( memory_model::memory_order_relaxed ); - assert( static_cast( cback_ - front ) < capacity()); + assert( static_cast( cback_ - front ) <= capacity()); if ( static_cast( cback_ - front ) < count ) { cback_ = back_.load( memory_model::memory_order_acquire ); @@ -388,10 +388,10 @@ namespace cds { namespace container { Returns \p true if success or \p false if not enough space in the ring */ template - typename std::enable_if< std::is_assignable::value, bool>::type + typename std::enable_if< std::is_move_assignable::value, bool>::type pop( Q* arr, size_t count ) { - return pop( arr, count, []( Q& dest, value_type& src ) { dest = src; } ); + return pop( arr, count, []( Q& dest, value_type& src ) { dest = std::move(src); } ); } /// Dequeues an element from the ring to \p val @@ -402,7 +402,7 @@ namespace cds { namespace container { Returns \p false if the ring is full or \p true otherwise. */ template - typename std::enable_if< std::is_assignable::value, bool>::type + typename std::enable_if< std::is_move_assignable::value, bool>::type dequeue( Q& val ) { return pop( &val, 1 ); @@ -410,7 +410,7 @@ namespace cds { namespace container { /// Synonym for \p dequeue( Q& ) template - typename std::enable_if< std::is_assignable::value, bool>::type + typename std::enable_if< std::is_move_assignable::value, bool>::type pop( Q& val ) { return dequeue( val ); @@ -433,7 +433,7 @@ namespace cds { namespace container { bool dequeue_with( Func f ) { counter_type front = front_.load( memory_model::memory_order_relaxed ); - assert( static_cast( cback_ - front ) < capacity()); + assert( static_cast( cback_ - front ) <= capacity()); if ( cback_ - front < 1 ) { cback_ = back_.load( memory_model::memory_order_acquire ); @@ -466,7 +466,7 @@ namespace cds { namespace container { value_type* front() { counter_type front = front_.load( memory_model::memory_order_relaxed ); - assert( static_cast( cback_ - front ) < capacity()); + assert( static_cast( cback_ - front ) <= capacity()); if ( cback_ - front < 1 ) { cback_ = back_.load( memory_model::memory_order_acquire ); @@ -687,7 +687,7 @@ namespace cds { namespace container { size_t real_size = calc_real_size( size ); // check if we can reserve real_size bytes - assert( real_size < capacity()); + assert( real_size <= capacity()); counter_type back = back_.load( memory_model::memory_order_relaxed ); assert( static_cast( back - pfront_ ) <= capacity()); @@ -777,7 +777,7 @@ namespace cds { namespace container { uint8_t* reserved = buffer_.buffer() + buffer_.mod( back ); size_t real_size = calc_real_size( *reinterpret_cast( reserved )); - assert( real_size < capacity()); + assert( real_size <= capacity()); back_.store( back + real_size, memory_model::memory_order_release ); } @@ -805,7 +805,7 @@ namespace cds { namespace container { std::pair front() { counter_type front = front_.load( memory_model::memory_order_relaxed ); - assert( static_cast( cback_ - front ) < capacity()); + assert( static_cast( cback_ - front ) <= capacity()); if ( cback_ - front < sizeof( size_t )) { cback_ = back_.load( memory_model::memory_order_acquire ); diff --git a/cds/opt/buffer.h b/cds/opt/buffer.h index 33ae088a0..cb41938be 100644 --- a/cds/opt/buffer.h +++ b/cds/opt/buffer.h @@ -338,7 +338,7 @@ namespace cds { namespace opt { uninitialized_dynamic_buffer( size_t nCapacity ) : m_nCapacity( c_bExp2 ? beans::ceil2(nCapacity) : nCapacity ) { - assert( m_nCapacity >= 2 ); + assert( m_nCapacity >= 1 ); // Capacity must be power of 2 assert( !c_bExp2 || (m_nCapacity & (m_nCapacity - 1)) == 0 ); @@ -464,7 +464,7 @@ namespace cds { namespace opt { initialized_dynamic_buffer( size_t nCapacity ) : m_nCapacity( c_bExp2 ? beans::ceil2(nCapacity) : nCapacity ) { - assert( m_nCapacity >= 2 ); + assert( m_nCapacity >= 1 ); // Capacity must be power of 2 assert( !c_bExp2 || (m_nCapacity & (m_nCapacity - 1)) == 0 ); diff --git a/test/unit/queue/weak_ringbuffer.cpp b/test/unit/queue/weak_ringbuffer.cpp index 71949a569..1cb1e6b45 100644 --- a/test/unit/queue/weak_ringbuffer.cpp +++ b/test/unit/queue/weak_ringbuffer.cpp @@ -213,6 +213,26 @@ namespace { } }; + TEST_F( WeakRingBuffer, one_sized ) + { + typedef cds::container::WeakRingBuffer< int > test_queue; + + test_queue q( 1 ); + test( q ); + } + + TEST_F( WeakRingBuffer, one_sized_static ) + { + struct traits: public cds::container::weak_ringbuffer::traits + { + typedef cds::opt::v::uninitialized_static_buffer buffer; + }; + typedef cds::container::WeakRingBuffer< int, traits > test_queue; + + test_queue q; + test( q ); + } + TEST_F( WeakRingBuffer, defaulted ) { typedef cds::container::WeakRingBuffer< int > test_queue; @@ -222,6 +242,62 @@ namespace { test_array( q ); } + struct MoveCopyNode { + MoveCopyNode() = default; + MoveCopyNode(const MoveCopyNode&) { + copy_count++; + } + MoveCopyNode& operator=(const MoveCopyNode&) { + copy_count++; + return *this; + } + MoveCopyNode(MoveCopyNode&&) { + move_count++; + } + MoveCopyNode& operator=(MoveCopyNode&&) { + move_count++; + return *this; + } + + static size_t copy_count; + static size_t move_count; + }; + + size_t MoveCopyNode::copy_count = 0; + size_t MoveCopyNode::move_count = 0; + + TEST_F( WeakRingBuffer, move_only ) + { + MoveCopyNode::copy_count = 0; + MoveCopyNode::move_count = 0; + typedef cds::container::WeakRingBuffer< MoveCopyNode > test_queue; + + test_queue q( 128 ); + q.enqueue(MoveCopyNode{}); + ASSERT_EQ(MoveCopyNode::move_count, 1); + ASSERT_EQ(MoveCopyNode::copy_count, 0); + q.push(MoveCopyNode{}); + ASSERT_EQ(MoveCopyNode::move_count, 2); + ASSERT_EQ(MoveCopyNode::copy_count, 0); + MoveCopyNode arr[12]{}; + q.push(arr, 12); + ASSERT_EQ(MoveCopyNode::move_count, 2); + ASSERT_EQ(MoveCopyNode::copy_count, 12); + + MoveCopyNode::copy_count = 0; + MoveCopyNode::move_count = 0; + + MoveCopyNode node; + q.dequeue(node); + ASSERT_EQ(MoveCopyNode::move_count, 1); + ASSERT_EQ(MoveCopyNode::copy_count, 0); + q.pop(node); + ASSERT_EQ(MoveCopyNode::move_count, 2); + ASSERT_EQ(MoveCopyNode::copy_count, 0); + + q.pop_front(); // does not trigger move or copy + } + TEST_F( WeakRingBuffer, stat ) { struct traits: public cds::container::weak_ringbuffer::traits