Added WeakRingBuffer - a single-producer/single-consumer queue based on ring buffer
[libcds.git] / test / unit / queue / weak_ringbuffer.cpp
1 /*
2     This file is a part of libcds - Concurrent Data Structures library
3
4     (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2017
5
6     Source code repo: http://github.com/khizmax/libcds/
7     Download: http://sourceforge.net/projects/libcds/files/
8
9     Redistribution and use in source and binary forms, with or without
10     modification, are permitted provided that the following conditions are met:
11
12     * Redistributions of source code must retain the above copyright notice, this
13     list of conditions and the following disclaimer.
14
15     * Redistributions in binary form must reproduce the above copyright notice,
16     this list of conditions and the following disclaimer in the documentation
17     and/or other materials provided with the distribution.
18
19     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20     AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21     IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23     FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24     DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28     OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "test_bounded_queue.h"
32
33 #include <cds/container/weak_ringbuffer.h>
34
35 namespace {
36     namespace cc = cds::container;
37
38     class WeakRingBuffer: public cds_test::bounded_queue
39     {
40     public:
41         template <typename Queue>
42         void test_array( Queue& q )
43         {
44             typedef typename Queue::value_type value_type;
45
46             const size_t nSize = q.capacity();
47             static const size_t nArrSize = 16;
48             const size_t nArrCount = nSize / nArrSize;
49
50             {
51                 value_type el[nArrSize];
52
53                 // batch push
54                 for ( size_t i = 0; i < nSize; i += nArrSize ) {
55                     for ( size_t k = 0; k < nArrSize; ++k )
56                         el[k] = static_cast<value_type>( i + k );
57
58                     if ( i + nArrSize <= nSize ) {
59                         ASSERT_TRUE( q.push( el, nArrSize ) );
60                     }
61                     else {
62                         ASSERT_FALSE( q.push( el, nArrSize ) );
63                     }
64                 }
65
66                 ASSERT_TRUE( !q.empty() );
67                 if ( nSize % nArrSize != 0 ) {
68                     ASSERT_FALSE( q.full() );
69                     ASSERT_CONTAINER_SIZE( q, nArrCount * nArrSize );
70                     for ( size_t i = nArrCount * nArrSize; i < nSize; ++i ) {
71                         ASSERT_TRUE( q.enqueue( static_cast<value_type>( i ) ) );
72                     }
73                 }
74                 ASSERT_TRUE( q.full() );
75                 ASSERT_CONTAINER_SIZE( q, nSize );
76
77                 // batch pop
78                 value_type expected = 0;
79                 while ( q.pop( el, nArrSize ) ) {
80                     for ( size_t i = 0; i < nArrSize; ++i ) {
81                         ASSERT_EQ( el[i], expected );
82                         ++expected;
83                     }
84                 }
85
86                 if ( nSize % nArrSize == 0 ) {
87                     ASSERT_TRUE( q.empty() );
88                 }
89                 else {
90                     ASSERT_FALSE( q.empty() );
91                     ASSERT_CONTAINER_SIZE( q, nSize % nArrSize );
92                     q.clear();
93                 }
94                 ASSERT_TRUE( q.empty() );
95                 ASSERT_FALSE( q.full() );
96                 ASSERT_CONTAINER_SIZE( q, 0u );
97             }
98
99             {
100                 // batch push with functor
101                 size_t el[nArrSize];
102
103                 auto func_push = []( value_type& dest, size_t src ) { dest = static_cast<value_type>( src * 10 ); };
104                 for ( size_t i = 0; i < nSize; i += nArrSize ) {
105                     for ( size_t k = 0; k < nArrSize; ++k )
106                         el[k] = i + k;
107
108                     if ( i + nArrSize <= nSize ) {
109                         ASSERT_TRUE( q.push( el, nArrSize, func_push ) );
110                     }
111                     else {
112                         ASSERT_FALSE( q.push( el, nArrSize, func_push ) );
113                     }
114                 }
115
116                 ASSERT_TRUE( !q.empty() );
117                 if ( nSize % nArrSize != 0 ) {
118                     ASSERT_FALSE( q.full() );
119                     ASSERT_CONTAINER_SIZE( q, nArrCount * nArrSize );
120                     for ( size_t i = nArrCount * nArrSize; i < nSize; ++i ) {
121                         ASSERT_TRUE( q.push( &i, 1, func_push ) );
122                     }
123                 }
124                 ASSERT_TRUE( q.full() );
125                 ASSERT_CONTAINER_SIZE( q, nSize );
126
127                 // batch pop with functor
128                 auto func_pop = []( size_t& dest, value_type src ) { dest = static_cast<size_t>( src / 10 ); };
129                 size_t expected = 0;
130                 while ( q.pop( el, nArrSize, func_pop ) ) {
131                     for ( size_t i = 0; i < nArrSize; ++i ) {
132                         ASSERT_EQ( el[i], expected );
133                         ++expected;
134                     }
135                 }
136
137                 if ( nSize % nArrSize == 0 ) {
138                     ASSERT_TRUE( q.empty() );
139                 }
140                 else {
141                     ASSERT_FALSE( q.empty() );
142                     ASSERT_CONTAINER_SIZE( q, nSize % nArrSize );
143                     size_t v;
144                     while ( q.pop( &v, 1, func_pop ) ) {
145                         ASSERT_EQ( v, expected );
146                         ++expected;
147                     }
148                 }
149                 ASSERT_TRUE( q.empty() );
150                 ASSERT_FALSE( q.full() );
151                 ASSERT_CONTAINER_SIZE( q, 0u );
152
153                 // front/pop_front
154                 for ( size_t i = 0; i < nSize; i += nArrSize ) {
155                     for ( size_t k = 0; k < nArrSize; ++k )
156                         el[k] = i + k;
157
158                     if ( i + nArrSize <= nSize ) {
159                         ASSERT_TRUE( q.push( el, nArrSize, func_push ) );
160                     }
161                     else {
162                         ASSERT_FALSE( q.push( el, nArrSize, func_push ) );
163                     }
164                 }
165
166                 ASSERT_TRUE( !q.empty() );
167                 if ( nSize % nArrSize != 0 ) {
168                     ASSERT_FALSE( q.full() );
169                     ASSERT_CONTAINER_SIZE( q, nArrCount * nArrSize );
170                     for ( size_t i = nArrCount * nArrSize; i < nSize; ++i ) {
171                         ASSERT_TRUE( q.push( &i, 1, func_push ) );
172                     }
173                 }
174                 ASSERT_TRUE( q.full() );
175                 ASSERT_CONTAINER_SIZE( q, nSize );
176
177                 value_type cur = 0;
178                 while ( !q.empty() ) {
179                     value_type* front = q.front();
180                     ASSERT_TRUE( front != nullptr );
181                     ASSERT_EQ( cur, *front );
182                     ASSERT_TRUE( q.pop_front() );
183                     cur += 10;
184                 }
185
186                 ASSERT_TRUE( q.empty() );
187                 ASSERT_TRUE( q.front() == nullptr );
188                 ASSERT_FALSE( q.pop_front() );
189             }
190         }
191     };
192
193     TEST_F( WeakRingBuffer, defaulted )
194     {
195         typedef cds::container::WeakRingBuffer< int > test_queue;
196
197         test_queue q( 128 );
198         test( q );
199         test_array( q );
200     }
201
202     TEST_F( WeakRingBuffer, stat )
203     {
204         struct traits: public cds::container::weak_ringbuffer::traits
205         {
206             typedef cds::opt::v::uninitialized_static_buffer<int, 128> buffer;
207         };
208         typedef cds::container::WeakRingBuffer< int, traits > test_queue;
209
210         test_queue q;
211         test( q );
212         test_array( q );
213     }
214
215     TEST_F( WeakRingBuffer, dynamic )
216     {
217         struct traits: public cds::container::weak_ringbuffer::traits
218         {
219             typedef cds::opt::v::uninitialized_dynamic_buffer<int> buffer;
220         };
221         typedef cds::container::WeakRingBuffer< int, traits > test_queue;
222
223         test_queue q( 128 );
224         test( q );
225         test_array( q );
226     }
227
228     TEST_F( WeakRingBuffer, dynamic_mod )
229     {
230         struct traits: public cds::container::weak_ringbuffer::traits
231         {
232             typedef cds::opt::v::uninitialized_dynamic_buffer<int, CDS_DEFAULT_ALLOCATOR, false> buffer;
233         };
234         typedef cds::container::WeakRingBuffer< int, traits > test_queue;
235
236         test_queue q( 100 );
237         test( q );
238         test_array( q );
239     }
240
241     TEST_F( WeakRingBuffer, dynamic_padding )
242     {
243         struct traits: public cds::container::weak_ringbuffer::traits
244         {
245             typedef cds::opt::v::uninitialized_dynamic_buffer<int> buffer;
246             enum { padding = 32 };
247         };
248         typedef cds::container::WeakRingBuffer< int, traits > test_queue;
249
250         test_queue q( 128 );
251         test( q );
252         test_array( q );
253     }
254
255 } // namespace