7718dad045f9e14ee6442a5ad31ff918c9384fc5
[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 #include <cds_test/fixture.h>
35
36 namespace {
37     namespace cc = cds::container;
38
39     class WeakRingBuffer: public cds_test::bounded_queue
40     {
41     public:
42         template <typename Queue>
43         void test_array( Queue& q )
44         {
45             typedef typename Queue::value_type value_type;
46
47             const size_t nSize = q.capacity();
48             static const size_t nArrSize = 16;
49             const size_t nArrCount = nSize / nArrSize;
50
51             {
52                 value_type el[nArrSize];
53
54                 for ( unsigned pass = 0; pass < 3; ++pass ) {
55                     // batch push
56                     for ( size_t i = 0; i < nSize; i += nArrSize ) {
57                         for ( size_t k = 0; k < nArrSize; ++k )
58                             el[k] = static_cast<value_type>( i + k );
59
60                         if ( i + nArrSize <= nSize ) {
61                             ASSERT_TRUE( q.push( el, nArrSize ) );
62                         }
63                         else {
64                             ASSERT_FALSE( q.push( el, nArrSize ) );
65                         }
66                     }
67
68                     ASSERT_TRUE( !q.empty() );
69                     if ( nSize % nArrSize != 0 ) {
70                         ASSERT_FALSE( q.full() );
71                         ASSERT_CONTAINER_SIZE( q, nArrCount * nArrSize );
72                         for ( size_t i = nArrCount * nArrSize; i < nSize; ++i ) {
73                             ASSERT_TRUE( q.enqueue( static_cast<value_type>( i ) ) );
74                         }
75                     }
76                     ASSERT_TRUE( q.full() );
77                     ASSERT_CONTAINER_SIZE( q, nSize );
78
79                     // batch pop
80                     value_type expected = 0;
81                     while ( q.pop( el, nArrSize ) ) {
82                         for ( size_t i = 0; i < nArrSize; ++i ) {
83                             ASSERT_EQ( el[i], expected );
84                             ++expected;
85                         }
86                     }
87
88                     if ( nSize % nArrSize == 0 ) {
89                         ASSERT_TRUE( q.empty() );
90                     }
91                     else {
92                         ASSERT_FALSE( q.empty() );
93                         ASSERT_CONTAINER_SIZE( q, nSize % nArrSize );
94                         q.clear();
95                     }
96                     ASSERT_TRUE( q.empty() );
97                     ASSERT_FALSE( q.full() );
98                     ASSERT_CONTAINER_SIZE( q, 0u );
99                 }
100             }
101
102             {
103                 // batch push with functor
104                 size_t el[nArrSize];
105
106                 auto func_push = []( value_type& dest, size_t src ) { dest = static_cast<value_type>( src * 10 ); };
107
108                 for ( unsigned pass = 0; pass < 3; ++pass ) {
109                     for ( size_t i = 0; i < nSize; i += nArrSize ) {
110                         for ( size_t k = 0; k < nArrSize; ++k )
111                             el[k] = i + k;
112
113                         if ( i + nArrSize <= nSize ) {
114                             ASSERT_TRUE( q.push( el, nArrSize, func_push ) );
115                         }
116                         else {
117                             ASSERT_FALSE( q.push( el, nArrSize, func_push ) );
118                         }
119                     }
120
121                     ASSERT_TRUE( !q.empty() );
122                     if ( nSize % nArrSize != 0 ) {
123                         ASSERT_FALSE( q.full() );
124                         ASSERT_CONTAINER_SIZE( q, nArrCount * nArrSize );
125                         for ( size_t i = nArrCount * nArrSize; i < nSize; ++i ) {
126                             ASSERT_TRUE( q.push( &i, 1, func_push ) );
127                         }
128                     }
129                     ASSERT_TRUE( q.full() );
130                     ASSERT_CONTAINER_SIZE( q, nSize );
131
132                     // batch pop with functor
133                     auto func_pop = []( size_t& dest, value_type src ) { dest = static_cast<size_t>( src / 10 ); };
134                     size_t expected = 0;
135                     while ( q.pop( el, nArrSize, func_pop ) ) {
136                         for ( size_t i = 0; i < nArrSize; ++i ) {
137                             ASSERT_EQ( el[i], expected );
138                             ++expected;
139                         }
140                     }
141
142                     if ( nSize % nArrSize == 0 ) {
143                         ASSERT_TRUE( q.empty() );
144                     }
145                     else {
146                         ASSERT_FALSE( q.empty() );
147                         ASSERT_CONTAINER_SIZE( q, nSize % nArrSize );
148                         size_t v;
149                         while ( q.pop( &v, 1, func_pop ) ) {
150                             ASSERT_EQ( v, expected );
151                             ++expected;
152                         }
153                     }
154                     ASSERT_TRUE( q.empty() );
155                     ASSERT_FALSE( q.full() );
156                     ASSERT_CONTAINER_SIZE( q, 0u );
157                 }
158
159                 // front/pop_front
160                 for ( unsigned pass = 0; pass < 3; ++pass ) {
161                     for ( size_t i = 0; i < nSize; i += nArrSize ) {
162                         for ( size_t k = 0; k < nArrSize; ++k )
163                             el[k] = i + k;
164
165                         if ( i + nArrSize <= nSize ) {
166                             ASSERT_TRUE( q.push( el, nArrSize, func_push ) );
167                         }
168                         else {
169                             ASSERT_FALSE( q.push( el, nArrSize, func_push ) );
170                         }
171                     }
172
173                     ASSERT_TRUE( !q.empty() );
174                     if ( nSize % nArrSize != 0 ) {
175                         ASSERT_FALSE( q.full() );
176                         ASSERT_CONTAINER_SIZE( q, nArrCount * nArrSize );
177                         for ( size_t i = nArrCount * nArrSize; i < nSize; ++i ) {
178                             ASSERT_TRUE( q.push( &i, 1, func_push ) );
179                         }
180                     }
181                     ASSERT_TRUE( q.full() );
182                     ASSERT_CONTAINER_SIZE( q, nSize );
183
184                     value_type cur = 0;
185                     while ( !q.empty() ) {
186                         value_type* front = q.front();
187                         ASSERT_TRUE( front != nullptr );
188                         ASSERT_EQ( cur, *front );
189                         ASSERT_TRUE( q.pop_front() );
190                         cur += 10;
191                     }
192
193                     ASSERT_TRUE( q.empty() );
194                     ASSERT_TRUE( q.front() == nullptr );
195                     ASSERT_FALSE( q.pop_front() );
196                 }
197             }
198         }
199
200         template <typename Queue>
201         void test_varsize_buffer( Queue& q )
202         {
203             size_t const capacity = q.capacity();
204
205             ASSERT_TRUE( q.empty() );
206             ASSERT_EQ( q.size(), 0u );
207             ASSERT_TRUE( q.front().first == nullptr );
208             ASSERT_FALSE( q.pop_front() );
209
210             size_t total_push = 0;
211             uint8_t chfill = 0;
212             while ( total_push < capacity * 4 ) {
213                 unsigned buf_size = cds_test::fixture::rand( static_cast<unsigned>( capacity / 4 )) + 1;
214                 total_push += buf_size;
215
216                 void* buf = q.back( buf_size );
217                 ASSERT_TRUE( buf != nullptr );
218
219                 memset( buf, chfill, buf_size );
220                 q.push_back();
221
222                 ASSERT_GE( q.size(), buf_size );
223
224                 auto pair = q.front();
225                 ASSERT_TRUE( pair.first != nullptr );
226                 ASSERT_EQ( pair.second, buf_size );
227                 for ( size_t i = 0; i < pair.second; ++i )
228                     ASSERT_EQ( *reinterpret_cast<uint8_t*>( pair.first ), chfill );
229
230                 ASSERT_TRUE( q.pop_front() );
231                 ASSERT_FALSE( q.pop_front() );
232             }
233
234             ASSERT_TRUE( q.empty() );
235             ASSERT_EQ( q.size(), 0u );
236             ASSERT_TRUE( q.front().first == nullptr );
237             ASSERT_FALSE( q.pop_front() );
238         }
239     };
240
241     TEST_F( WeakRingBuffer, defaulted )
242     {
243         typedef cds::container::WeakRingBuffer< int > test_queue;
244
245         test_queue q( 128 );
246         test( q );
247         test_array( q );
248     }
249
250     TEST_F( WeakRingBuffer, stat )
251     {
252         struct traits: public cds::container::weak_ringbuffer::traits
253         {
254             typedef cds::opt::v::uninitialized_static_buffer<int, 128> buffer;
255         };
256         typedef cds::container::WeakRingBuffer< int, traits > test_queue;
257
258         test_queue q;
259         test( q );
260         test_array( q );
261     }
262
263     TEST_F( WeakRingBuffer, dynamic )
264     {
265         struct traits: public cds::container::weak_ringbuffer::traits
266         {
267             typedef cds::opt::v::uninitialized_dynamic_buffer<int> buffer;
268         };
269         typedef cds::container::WeakRingBuffer< int, traits > test_queue;
270
271         test_queue q( 128 );
272         test( q );
273         test_array( q );
274     }
275
276     TEST_F( WeakRingBuffer, dynamic_mod )
277     {
278         struct traits: public cds::container::weak_ringbuffer::traits
279         {
280             typedef cds::opt::v::uninitialized_dynamic_buffer<int, CDS_DEFAULT_ALLOCATOR, false> buffer;
281         };
282         typedef cds::container::WeakRingBuffer< int, traits > test_queue;
283
284         test_queue q( 100 );
285         test( q );
286         test_array( q );
287     }
288
289     TEST_F( WeakRingBuffer, dynamic_padding )
290     {
291         struct traits: public cds::container::weak_ringbuffer::traits
292         {
293             typedef cds::opt::v::uninitialized_dynamic_buffer<int> buffer;
294             enum { padding = 32 };
295         };
296         typedef cds::container::WeakRingBuffer< int, traits > test_queue;
297
298         test_queue q( 128 );
299         test( q );
300         test_array( q );
301     }
302
303     TEST_F( WeakRingBuffer, var_sized )
304     {
305         typedef cds::container::WeakRingBuffer< void > test_queue;
306
307         test_queue q( 1024 * 64 );
308         test_varsize_buffer( q );
309     }
310
311     TEST_F( WeakRingBuffer, var_sized_static )
312     {
313         struct traits: public cds::container::weak_ringbuffer::traits
314         {
315             typedef cds::opt::v::uninitialized_static_buffer<int, 1024 * 64> buffer;
316         };
317         typedef cds::container::WeakRingBuffer< void, traits > test_queue;
318
319         test_queue q;
320         test_varsize_buffer( q );
321     }
322
323 } // namespace