Small fixes in split_bitstring algo
[libcds.git] / tests / test-hdr / misc / split_bitstring.cpp
1 //$$CDS-header$$
2
3 #include "cppunit/cppunit_proxy.h"
4
5 #include <cds/algo/split_bitstring.h>
6
7 class Split_bitstrig : public CppUnitMini::TestCase
8 {
9 private:
10     bool is_big_endian()
11     {
12         union {
13             uint32_t ui;
14             uint8_t  ch;
15         } byte_order;
16         byte_order.ui = 0xFF000001;
17
18         return byte_order.ch != 0x01;
19     }
20 protected:
21
22     void cut_uint()
23     {
24         if ( is_big_endian() )
25             cut_uint_be();
26         else
27             cut_uint_le();
28     }
29
30     void cut_uint16()
31     {
32         if ( is_big_endian() )
33             cut_small_be<uint16_t>();
34         else
35             cut_small_le<uint16_t>();
36     }
37
38     void cut_uint_le()
39     {
40         CPPUNIT_MSG("little-endian byte order");
41
42         typedef cds::algo::split_bitstring< size_t > split_bitstring;
43
44         size_t src = sizeof(src) == 8 ? 0xFEDCBA9876543210 : 0x76543210;
45         split_bitstring splitter(src);
46         size_t res;
47
48         // Trivial case
49         CPPUNIT_ASSERT( !splitter.eos() );
50         CPPUNIT_ASSERT( splitter );
51         res = splitter.cut(sizeof(src) * 8);
52         CPPUNIT_ASSERT_EX( res == src, "src=" << src << ", result=" << res );
53         CPPUNIT_ASSERT( splitter.eos() );
54         CPPUNIT_ASSERT( !splitter );
55         CPPUNIT_ASSERT(splitter.safe_cut(sizeof(src) * 8) == 0 );
56         CPPUNIT_ASSERT( splitter.eos() );
57         CPPUNIT_ASSERT( !splitter );
58         splitter.reset();
59         CPPUNIT_ASSERT( !splitter.eos() );
60         CPPUNIT_ASSERT( splitter );
61         res = splitter.cut(sizeof(src) * 8);
62         CPPUNIT_ASSERT_EX( res == src, "src=" << src << ", result=" << res );
63         CPPUNIT_ASSERT( splitter.eos() );
64         CPPUNIT_ASSERT( !splitter );
65         CPPUNIT_ASSERT(splitter.safe_cut(sizeof(src) * 8) == 0 );
66         CPPUNIT_ASSERT( splitter.eos() );
67         CPPUNIT_ASSERT( !splitter );
68
69         // Cut each hex digit
70         splitter.reset();
71         for ( size_t i = 0; i < sizeof(size_t) * 2; ++i ) {
72             CPPUNIT_ASSERT( !splitter.eos() );
73             CPPUNIT_ASSERT( splitter );
74             CPPUNIT_ASSERT( splitter.cut( 4 ) == i );
75         }
76         CPPUNIT_ASSERT( splitter.eos() );
77         CPPUNIT_ASSERT( !splitter );
78
79         // by one bit
80         {
81             splitter.reset();
82             res = 0;
83             for ( size_t i = 0; i < sizeof(size_t) * 8; ++i ) {
84                 CPPUNIT_ASSERT( !splitter.eos() );
85                 CPPUNIT_ASSERT( splitter );
86                 res = res + (splitter.cut( 1 ) << i);
87             }
88             CPPUNIT_ASSERT( splitter.eos() );
89             CPPUNIT_ASSERT( !splitter );
90             CPPUNIT_ASSERT( res == src );
91         }
92
93         // random cut
94         {
95             for ( size_t k = 0; k < 100; ++k ) {
96                 splitter.reset();
97                 res = 0;
98                 size_t shift = 0;
99                 while ( splitter ) {
100                     CPPUNIT_ASSERT( !splitter.eos() );
101                     CPPUNIT_ASSERT( splitter );
102                     int bits = rand() % 16;
103                     res = res + ( splitter.safe_cut( bits ) << shift );
104                     shift += bits;
105                 }
106                 CPPUNIT_ASSERT( splitter.eos() );
107                 CPPUNIT_ASSERT( !splitter );
108                 CPPUNIT_ASSERT( res == src );
109             }
110         }
111     }
112
113     void cut_uint_be()
114     {
115         CPPUNIT_MSG("big-endian byte order");
116
117         typedef cds::algo::split_bitstring< size_t > split_bitstring;
118
119         size_t src = sizeof(src) == 8 ? 0xFEDCBA9876543210 : 0x76543210;
120         split_bitstring splitter(src);
121         size_t res;
122
123         // Trivial case
124         CPPUNIT_ASSERT( !splitter.eos() );
125         CPPUNIT_ASSERT( splitter );
126         res = splitter.cut(sizeof(src) * 8);
127         CPPUNIT_ASSERT_EX( res == src, "src=" << src << ", result=" << res );
128         CPPUNIT_ASSERT( splitter.eos() );
129         CPPUNIT_ASSERT( !splitter );
130         CPPUNIT_ASSERT(splitter.safe_cut(sizeof(src) * 8) == 0 );
131         CPPUNIT_ASSERT( splitter.eos() );
132         CPPUNIT_ASSERT( !splitter );
133         splitter.reset();
134         CPPUNIT_ASSERT( !splitter.eos() );
135         CPPUNIT_ASSERT( splitter );
136         res = splitter.cut(sizeof(src) * 8);
137         CPPUNIT_ASSERT_EX( res == src, "src=" << src << ", result=" << res );
138         CPPUNIT_ASSERT( splitter.eos() );
139         CPPUNIT_ASSERT( !splitter );
140         CPPUNIT_ASSERT(splitter.safe_cut(sizeof(src) * 8) == 0 );
141         CPPUNIT_ASSERT( splitter.eos() );
142         CPPUNIT_ASSERT( !splitter );
143
144         // Cut each hex digit
145         splitter.reset();
146         for ( size_t i = 0; i < sizeof(size_t) * 2; ++i ) {
147             CPPUNIT_ASSERT( !splitter.eos() );
148             CPPUNIT_ASSERT( splitter );
149             CPPUNIT_ASSERT( splitter.cut( 4 ) == 0x0F - i );
150         }
151         CPPUNIT_ASSERT( splitter.eos() );
152         CPPUNIT_ASSERT( !splitter );
153
154         // by one bit
155         {
156             splitter.reset();
157             res = 0;
158             for ( size_t i = 0; i < sizeof(size_t) * 8; ++i ) {
159                 CPPUNIT_ASSERT( !splitter.eos() );
160                 CPPUNIT_ASSERT( splitter );
161                 res = (res << 1) + splitter.cut( 1 );
162             }
163             CPPUNIT_ASSERT( splitter.eos() );
164             CPPUNIT_ASSERT( !splitter );
165             CPPUNIT_ASSERT( res == src );
166         }
167
168         // random cut
169         {
170             for ( size_t k = 0; k < 100; ++k ) {
171                 splitter.reset();
172                 res = 0;
173                 while ( splitter ) {
174                     CPPUNIT_ASSERT( !splitter.eos() );
175                     CPPUNIT_ASSERT( splitter );
176                     int bits = rand() % 16;
177                     res = (res << bits) + splitter.safe_cut( bits );
178                 }
179                 CPPUNIT_ASSERT( splitter.eos() );
180                 CPPUNIT_ASSERT( !splitter );
181                 CPPUNIT_ASSERT( res == src );
182             }
183         }
184     }
185
186
187 private:
188     template <typename PartUInt>
189     void cut_small_le()
190     {
191         CPPUNIT_MSG("little-endian byte order");
192         typedef PartUInt part_uint;
193
194         typedef cds::algo::split_bitstring< uint64_t, part_uint > split_bitstring;
195
196         uint64_t src = 0xFEDCBA9876543210;
197         split_bitstring splitter(src);
198         uint64_t res;
199
200         // Cut each hex digit
201         splitter.reset();
202         for ( size_t i = 0; i < sizeof(size_t) * 2; ++i ) {
203             CPPUNIT_ASSERT( !splitter.eos() );
204             CPPUNIT_ASSERT( splitter );
205             CPPUNIT_ASSERT( static_cast<size_t>(splitter.cut( 4 )) == i );
206         }
207         CPPUNIT_ASSERT( splitter.eos() );
208         CPPUNIT_ASSERT( !splitter );
209
210         // by one bit
211         {
212             splitter.reset();
213             res = 0;
214             for ( size_t i = 0; i < sizeof(size_t) * 8; ++i ) {
215                 CPPUNIT_ASSERT( !splitter.eos() );
216                 CPPUNIT_ASSERT( splitter );
217                 res = res + ( static_cast<uint64_t>(splitter.cut( 1 )) << i);
218             }
219             CPPUNIT_ASSERT( splitter.eos() );
220             CPPUNIT_ASSERT( !splitter );
221             CPPUNIT_ASSERT( res == src );
222         }
223
224         // random cut
225         {
226             for ( size_t k = 0; k < 100; ++k ) {
227                 splitter.reset();
228                 res = 0;
229                 size_t shift = 0;
230                 while ( splitter ) {
231                     CPPUNIT_ASSERT( !splitter.eos() );
232                     CPPUNIT_ASSERT( splitter );
233                     int bits = rand() % 16;
234                     res = res + ( static_cast<uint64_t>(splitter.safe_cut( bits )) << shift );
235                     shift += bits;
236                 }
237                 CPPUNIT_ASSERT( splitter.eos() );
238                 CPPUNIT_ASSERT( !splitter );
239                 CPPUNIT_ASSERT( res == src );
240             }
241         }
242     }
243
244     template <typename PartUInt>
245     void cut_small_be()
246     {
247         CPPUNIT_MSG("big-endian byte order");
248         typedef PartUInt part_uint;
249
250         typedef cds::algo::split_bitstring< uint64_t, part_uint > split_bitstring;
251
252         uint64_t src = 0xFEDCBA9876543210;
253         split_bitstring splitter(src);
254         uint64_t res;
255
256         // Cut each hex digit
257         splitter.reset();
258         for ( size_t i = 0; i < sizeof(size_t) * 2; ++i ) {
259             CPPUNIT_ASSERT( !splitter.eos() );
260             CPPUNIT_ASSERT( splitter );
261             CPPUNIT_ASSERT( splitter.cut( 4 ) == 0x0F - i );
262         }
263         CPPUNIT_ASSERT( splitter.eos() );
264         CPPUNIT_ASSERT( !splitter );
265
266         // by one bit
267         {
268             splitter.reset();
269             res = 0;
270             for ( size_t i = 0; i < sizeof(size_t) * 8; ++i ) {
271                 CPPUNIT_ASSERT( !splitter.eos() );
272                 CPPUNIT_ASSERT( splitter );
273                 res = (res << 1) + splitter.cut( 1 );
274             }
275             CPPUNIT_ASSERT( splitter.eos() );
276             CPPUNIT_ASSERT( !splitter );
277             CPPUNIT_ASSERT( res == src );
278         }
279
280         // random cut
281         {
282             for ( size_t k = 0; k < 100; ++k ) {
283                 splitter.reset();
284                 res = 0;
285                 while ( splitter ) {
286                     CPPUNIT_ASSERT( !splitter.eos() );
287                     CPPUNIT_ASSERT( splitter );
288                     int bits = rand() % 16;
289                     res = (res << bits) + splitter.safe_cut( bits );
290                 }
291                 CPPUNIT_ASSERT( splitter.eos() );
292                 CPPUNIT_ASSERT( !splitter );
293                 CPPUNIT_ASSERT( res == src );
294             }
295         }
296     }
297
298
299     CPPUNIT_TEST_SUITE(Split_bitstrig);
300         CPPUNIT_TEST(cut_uint)
301         CPPUNIT_TEST(cut_uint16)
302     CPPUNIT_TEST_SUITE_END();
303 };
304
305 CPPUNIT_TEST_SUITE_REGISTRATION(Split_bitstrig);