1 | // Boost CRC test program file ---------------------------------------------// |
2 | |
3 | // Copyright 2001, 2003, 2004 Daryle Walker. Use, modification, and |
4 | // distribution are subject to the Boost Software License, Version 1.0. (See |
5 | // accompanying file LICENSE_1_0.txt or a copy at |
6 | // <http://www.boost.org/LICENSE_1_0.txt>.) |
7 | |
8 | // See <http://www.boost.org/libs/crc/> for the library's home page. |
9 | |
10 | // Revision History |
11 | // 28 Aug 2004 Added CRC tests for polynominals shorter than 8 bits |
12 | // (Daryle Walker, by patch from Bert Klaps) |
13 | // 23 Aug 2003 Adjust to updated Test framework (Daryle Walker) |
14 | // 14 May 2001 Initial version (Daryle Walker) |
15 | |
16 | |
17 | #include <boost/crc.hpp> // for boost::crc_basic, etc. |
18 | #include <boost/config.hpp> // for BOOST_MSVC, etc. |
19 | #include <boost/cstdint.hpp> // for boost::uint16_t, etc. |
20 | #include <boost/integer.hpp> // for boost::uint_t |
21 | #include <boost/random/linear_congruential.hpp> // for boost::minstd_rand |
22 | #include <boost/core/lightweight_test.hpp> |
23 | #include <boost/timer/timer.hpp> // for boost::timer |
24 | |
25 | #include <algorithm> // for std::for_each, std::generate_n, std::count |
26 | #include <climits> // for CHAR_BIT |
27 | #include <cstddef> // for std::size_t |
28 | #include <iostream> // for std::cout (std::ostream and std::endl indirectly) |
29 | |
30 | |
31 | #if CHAR_BIT != 8 |
32 | #error The expected results assume an eight-bit byte. |
33 | #endif |
34 | |
35 | #if !(defined(BOOST_NO_DEPENDENT_TYPES_IN_TEMPLATE_VALUE_PARAMETERS) || (defined(BOOST_MSVC) && (BOOST_MSVC <= 1300))) |
36 | #define CRC_PARM_TYPE typename boost::uint_t<Bits>::fast |
37 | #else |
38 | #define CRC_PARM_TYPE unsigned long |
39 | #endif |
40 | |
41 | #if !defined(BOOST_MSVC) && !defined(__GNUC__) |
42 | #define PRIVATE_DECLARE_BOOST( TypeName ) using boost:: TypeName |
43 | #else |
44 | #define PRIVATE_DECLARE_BOOST( TypeName ) typedef boost:: TypeName TypeName |
45 | #endif |
46 | |
47 | |
48 | // Types |
49 | template < std::size_t Bits, CRC_PARM_TYPE TrPo, CRC_PARM_TYPE InRe, |
50 | CRC_PARM_TYPE FiXo, bool ReIn, bool ReRe > |
51 | class crc_tester |
52 | { |
53 | public: |
54 | // All the following were separate function templates, but they have |
55 | // been moved to class-static member functions of a class template |
56 | // because MS VC++ 6 can't handle function templates that can't |
57 | // deduce all their template arguments from their function arguments. |
58 | |
59 | typedef typename boost::uint_t<Bits>::fast value_type; |
60 | |
61 | static void master_test( char const *test_name, value_type expected ); |
62 | |
63 | private: |
64 | typedef boost::crc_optimal<Bits, TrPo, InRe, FiXo, ReIn, ReRe> |
65 | optimal_crc_type; |
66 | typedef boost::crc_basic<Bits> basic_crc_type; |
67 | |
68 | static void compute_test( value_type expected ); |
69 | static void interrupt_test( value_type expected ); |
70 | static void error_test(); |
71 | |
72 | }; // crc_tester |
73 | |
74 | // Global data |
75 | unsigned char const std_data[] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, |
76 | 0x38, 0x39 }; |
77 | std::size_t const std_data_len = sizeof( std_data ) / sizeof( std_data[0] ); |
78 | |
79 | boost::uint16_t const std_crc_ccitt_result = 0x29B1; |
80 | boost::uint16_t const std_crc_16_result = 0xBB3D; |
81 | boost::uint32_t const std_crc_32_result = 0xCBF43926; |
82 | |
83 | // Function prototypes |
84 | void timing_test(); |
85 | boost::uint32_t basic_crc32( void const *buffer, std::size_t byte_count ); |
86 | boost::uint32_t optimal_crc32( void const *buffer, std::size_t byte_count ); |
87 | boost::uint32_t quick_crc32( void const *buffer, std::size_t byte_count ); |
88 | boost::uint32_t quick_reflect( boost::uint32_t value, std::size_t bits ); |
89 | double time_trial( char const *name, |
90 | boost::uint32_t (*crc_func)(void const *, std::size_t), |
91 | boost::uint32_t expected, void const *data, std::size_t length ); |
92 | |
93 | void augmented_tests(); |
94 | boost::uint32_t native_to_big( boost::uint32_t x ); |
95 | boost::uint32_t big_to_native( boost::uint32_t x ); |
96 | |
97 | void small_crc_test1(); |
98 | void small_crc_test2(); |
99 | |
100 | |
101 | // Macro to compact code |
102 | #define PRIVATE_TESTER_NAME crc_tester<Bits, TrPo, InRe, FiXo, ReIn, ReRe> |
103 | |
104 | // Run a test on slow and fast CRC computers and function |
105 | template < std::size_t Bits, CRC_PARM_TYPE TrPo, CRC_PARM_TYPE InRe, |
106 | CRC_PARM_TYPE FiXo, bool ReIn, bool ReRe > |
107 | void |
108 | PRIVATE_TESTER_NAME::compute_test |
109 | ( |
110 | typename PRIVATE_TESTER_NAME::value_type expected |
111 | ) |
112 | { |
113 | std::cout << "\tDoing computation tests." << std::endl; |
114 | |
115 | optimal_crc_type fast_crc; |
116 | basic_crc_type slow_crc( TrPo, InRe, FiXo, ReIn, ReRe ); |
117 | value_type const func_result = boost::crc<Bits, TrPo, InRe, FiXo, ReIn, |
118 | ReRe>( std_data, std_data_len ); |
119 | |
120 | fast_crc.process_bytes( std_data, std_data_len ); |
121 | slow_crc.process_bytes( std_data, std_data_len ); |
122 | BOOST_TEST_EQ( fast_crc.checksum(), expected ); |
123 | BOOST_TEST_EQ( slow_crc.checksum(), expected ); |
124 | BOOST_TEST_EQ( func_result, expected ); |
125 | } |
126 | |
127 | // Run a test in two runs, and check all the inspectors |
128 | template < std::size_t Bits, CRC_PARM_TYPE TrPo, CRC_PARM_TYPE InRe, |
129 | CRC_PARM_TYPE FiXo, bool ReIn, bool ReRe > |
130 | void |
131 | PRIVATE_TESTER_NAME::interrupt_test |
132 | ( |
133 | typename PRIVATE_TESTER_NAME::value_type expected |
134 | ) |
135 | { |
136 | std::cout << "\tDoing interrupt tests." << std::endl; |
137 | |
138 | // Process the first half of the data (also test accessors) |
139 | optimal_crc_type fast_crc1; |
140 | basic_crc_type slow_crc1( fast_crc1.get_truncated_polynominal(), |
141 | fast_crc1.get_initial_remainder(), fast_crc1.get_final_xor_value(), |
142 | fast_crc1.get_reflect_input(), fast_crc1.get_reflect_remainder() ); |
143 | |
144 | BOOST_TEST_EQ( fast_crc1.get_interim_remainder(), |
145 | slow_crc1.get_initial_remainder() ); |
146 | |
147 | std::size_t const mid_way = std_data_len / 2; |
148 | unsigned char const * const std_data_end = std_data + std_data_len; |
149 | |
150 | fast_crc1.process_bytes( std_data, mid_way ); |
151 | slow_crc1.process_bytes( std_data, mid_way ); |
152 | BOOST_TEST_EQ( fast_crc1.checksum(), slow_crc1.checksum() ); |
153 | |
154 | // Process the second half of the data (also test accessors) |
155 | boost::crc_optimal<optimal_crc_type::bit_count, |
156 | optimal_crc_type::truncated_polynominal, optimal_crc_type::initial_remainder, |
157 | optimal_crc_type::final_xor_value, optimal_crc_type::reflect_input, |
158 | optimal_crc_type::reflect_remainder> |
159 | fast_crc2( fast_crc1.get_interim_remainder() ); |
160 | boost::crc_basic<basic_crc_type::bit_count> slow_crc2( |
161 | slow_crc1.get_truncated_polynominal(), slow_crc1.get_interim_remainder(), |
162 | slow_crc1.get_final_xor_value(), slow_crc1.get_reflect_input(), |
163 | slow_crc1.get_reflect_remainder() ); |
164 | |
165 | fast_crc2.process_block( std_data + mid_way, std_data_end ); |
166 | slow_crc2.process_block( std_data + mid_way, std_data_end ); |
167 | BOOST_TEST_EQ( fast_crc2.checksum(), slow_crc2.checksum() ); |
168 | BOOST_TEST_EQ( fast_crc2.checksum(), expected ); |
169 | BOOST_TEST_EQ( slow_crc2.checksum(), expected ); |
170 | } |
171 | |
172 | // Run a test to see if a single-bit error is detected |
173 | template < std::size_t Bits, CRC_PARM_TYPE TrPo, CRC_PARM_TYPE InRe, |
174 | CRC_PARM_TYPE FiXo, bool ReIn, bool ReRe > |
175 | void |
176 | PRIVATE_TESTER_NAME::error_test |
177 | ( |
178 | ) |
179 | { |
180 | PRIVATE_DECLARE_BOOST( uint32_t ); |
181 | |
182 | // A single-bit error is ensured to be detected if the polynominal |
183 | // has at least two bits set. The highest bit is what is removed |
184 | // to give the truncated polynominal, and it is always set. This |
185 | // means that the truncated polynominal needs at least one of its |
186 | // bits set, which implies that it cannot be zero. |
187 | if ( !(TrPo & boost::detail::low_bits_mask_c<Bits>::value) ) |
188 | { |
189 | BOOST_ERROR( "truncated CRC polymonial is zero" ); |
190 | } |
191 | |
192 | std::cout << "\tDoing error tests." << std::endl; |
193 | |
194 | // Create a random block of data |
195 | uint32_t ran_data[ 256 ]; |
196 | std::size_t const ran_length = sizeof(ran_data) / sizeof(ran_data[0]); |
197 | |
198 | std::generate_n( first: ran_data, n: ran_length, gen: boost::minstd_rand() ); |
199 | |
200 | // Create computers and compute the checksum of the data |
201 | optimal_crc_type fast_tester; |
202 | basic_crc_type slow_tester( TrPo, InRe, FiXo, ReIn, ReRe ); |
203 | |
204 | fast_tester.process_bytes( ran_data, sizeof(ran_data) ); |
205 | slow_tester.process_bytes( ran_data, sizeof(ran_data) ); |
206 | |
207 | uint32_t const fast_checksum = fast_tester.checksum(); |
208 | uint32_t const slow_checksum = slow_tester.checksum(); |
209 | |
210 | BOOST_TEST_EQ( fast_checksum, slow_checksum ); |
211 | |
212 | // Do the checksum again (and test resetting ability) |
213 | fast_tester.reset(); |
214 | slow_tester.reset( InRe ); |
215 | fast_tester.process_bytes( ran_data, sizeof(ran_data) ); |
216 | slow_tester.process_bytes( ran_data, sizeof(ran_data) ); |
217 | BOOST_TEST_EQ( fast_tester.checksum(), slow_tester.checksum() ); |
218 | BOOST_TEST_EQ( fast_tester.checksum(), fast_checksum ); |
219 | BOOST_TEST_EQ( slow_tester.checksum(), slow_checksum ); |
220 | |
221 | // Produce a single-bit error |
222 | ran_data[ ran_data[0] % ran_length ] ^= ( 1 << (ran_data[1] % 32) ); |
223 | |
224 | // Compute the checksum of the errorenous data |
225 | // (and continue testing resetting ability) |
226 | fast_tester.reset( InRe ); |
227 | slow_tester.reset(); |
228 | fast_tester.process_bytes( ran_data, sizeof(ran_data) ); |
229 | slow_tester.process_bytes( ran_data, sizeof(ran_data) ); |
230 | BOOST_TEST_EQ( fast_tester.checksum(), slow_tester.checksum() ); |
231 | BOOST_TEST_NE( fast_tester.checksum(), fast_checksum ); |
232 | BOOST_TEST_NE( slow_tester.checksum(), slow_checksum ); |
233 | } |
234 | |
235 | // Run the other CRC object tests |
236 | template < std::size_t Bits, CRC_PARM_TYPE TrPo, CRC_PARM_TYPE InRe, |
237 | CRC_PARM_TYPE FiXo, bool ReIn, bool ReRe > |
238 | void |
239 | PRIVATE_TESTER_NAME::master_test |
240 | ( |
241 | char const * test_name, |
242 | typename PRIVATE_TESTER_NAME::value_type expected |
243 | ) |
244 | { |
245 | std::cout << "Doing test suite for " << test_name << '.' << std::endl; |
246 | compute_test( expected ); |
247 | interrupt_test( expected ); |
248 | error_test(); |
249 | } |
250 | |
251 | // Undo limited macros |
252 | #undef PRIVATE_TESTER_NAME |
253 | |
254 | |
255 | // A CRC-32 computer based on crc_basic, for timing |
256 | boost::uint32_t |
257 | basic_crc32 |
258 | ( |
259 | void const * buffer, |
260 | std::size_t byte_count |
261 | ) |
262 | { |
263 | static boost::crc_basic<32> computer( 0x04C11DB7, 0xFFFFFFFF, 0xFFFFFFFF, |
264 | true, true ); |
265 | |
266 | computer.reset(); |
267 | computer.process_bytes( buffer, byte_count ); |
268 | return computer.checksum(); |
269 | } |
270 | |
271 | // A CRC-32 computer based on crc_optimal, for timing |
272 | inline |
273 | boost::uint32_t |
274 | optimal_crc32 |
275 | ( |
276 | void const * buffer, |
277 | std::size_t byte_count |
278 | ) |
279 | { |
280 | static boost::crc_32_type computer; |
281 | |
282 | computer.reset(); |
283 | computer.process_bytes( buffer, byte_count ); |
284 | return computer.checksum(); |
285 | } |
286 | |
287 | // Reflect the lower "bits" bits of a "value" |
288 | boost::uint32_t |
289 | quick_reflect |
290 | ( |
291 | boost::uint32_t value, |
292 | std::size_t bits |
293 | ) |
294 | { |
295 | boost::uint32_t reflection = 0; |
296 | for ( std::size_t i = 0 ; i < bits ; ++i ) |
297 | { |
298 | if ( value & (1u << i) ) |
299 | { |
300 | reflection |= 1 << ( bits - 1 - i ); |
301 | } |
302 | } |
303 | |
304 | return reflection; |
305 | } |
306 | |
307 | // A customized CRC-32 computer, for timing |
308 | boost::uint32_t |
309 | quick_crc32 |
310 | ( |
311 | void const * buffer, |
312 | std::size_t byte_count |
313 | ) |
314 | { |
315 | PRIVATE_DECLARE_BOOST( uint32_t ); |
316 | typedef unsigned char byte_type; |
317 | |
318 | // Compute the CRC table (first run only) |
319 | static bool did_init = false; |
320 | static uint32_t crc_table[ 1ul << CHAR_BIT ]; |
321 | if ( !did_init ) |
322 | { |
323 | uint32_t const value_high_bit = static_cast<uint32_t>(1) << 31u; |
324 | |
325 | byte_type dividend = 0; |
326 | do |
327 | { |
328 | uint32_t remainder = 0; |
329 | for ( byte_type mask = 1u << (CHAR_BIT - 1u) ; mask ; mask >>= 1 ) |
330 | { |
331 | if ( dividend & mask ) |
332 | { |
333 | remainder ^= value_high_bit; |
334 | } |
335 | |
336 | if ( remainder & value_high_bit ) |
337 | { |
338 | remainder <<= 1; |
339 | remainder ^= 0x04C11DB7u; |
340 | } |
341 | else |
342 | { |
343 | remainder <<= 1; |
344 | } |
345 | } |
346 | |
347 | crc_table[ quick_reflect(value: dividend, CHAR_BIT) ] |
348 | = quick_reflect( value: remainder, bits: 32 ); |
349 | } |
350 | while ( ++dividend ); |
351 | |
352 | did_init = true; |
353 | } |
354 | |
355 | // Compute the CRC of the data |
356 | uint32_t rem = 0xFFFFFFFF; |
357 | |
358 | byte_type const * const b_begin = static_cast<byte_type const *>( buffer ); |
359 | byte_type const * const b_end = b_begin + byte_count; |
360 | for ( byte_type const *p = b_begin ; p < b_end ; ++p ) |
361 | { |
362 | byte_type const byte_index = *p ^ rem; |
363 | rem >>= CHAR_BIT; |
364 | rem ^= crc_table[ byte_index ]; |
365 | } |
366 | |
367 | return ~rem; |
368 | } |
369 | |
370 | // Run an individual timing trial |
371 | double |
372 | time_trial |
373 | ( |
374 | char const * name, |
375 | boost::uint32_t (*crc_func)(void const *, std::size_t), |
376 | boost::uint32_t expected, |
377 | void const * data, |
378 | std::size_t length |
379 | ) |
380 | { |
381 | PRIVATE_DECLARE_BOOST( uint32_t ); |
382 | using std::cout; |
383 | |
384 | // Limits of a trial |
385 | static uint32_t const max_count = 1L << 16; // ~square-root of max |
386 | static double const max_time = 3.14159; // easy as pi(e) |
387 | |
388 | // Mark the trial |
389 | cout << '\t' << name << " CRC-32: " ; |
390 | |
391 | // Trial loop |
392 | uint32_t trial_count = 0, wrong_count = 0; |
393 | double elapsed_time = 0.0; |
394 | boost::timer::cpu_timer t; |
395 | |
396 | do |
397 | { |
398 | uint32_t const scratch = (*crc_func)( data, length ); |
399 | |
400 | if ( scratch != expected ) |
401 | { |
402 | ++wrong_count; |
403 | } |
404 | elapsed_time = t.elapsed().wall / 1e9; |
405 | ++trial_count; |
406 | } while ( (trial_count < max_count) && (elapsed_time < max_time) ); |
407 | |
408 | if ( wrong_count ) |
409 | { |
410 | BOOST_ERROR( "at least one time trial didn't match expected" ); |
411 | } |
412 | |
413 | // Report results |
414 | double const rate = trial_count / elapsed_time; |
415 | |
416 | cout << trial_count << " runs, " << elapsed_time << " s, " << rate |
417 | << " run/s" << std::endl; |
418 | return rate; |
419 | } |
420 | |
421 | // Time runs of Boost CRCs vs. a customized CRC function |
422 | void |
423 | timing_test |
424 | ( |
425 | ) |
426 | { |
427 | PRIVATE_DECLARE_BOOST( uint32_t ); |
428 | using std::cout; |
429 | using std::endl; |
430 | |
431 | cout << "Doing timing tests." << endl; |
432 | |
433 | // Create a random block of data |
434 | boost::int32_t ran_data[ 256 ]; |
435 | std::size_t const ran_length = sizeof(ran_data) / sizeof(ran_data[0]); |
436 | |
437 | std::generate_n( first: ran_data, n: ran_length, gen: boost::minstd_rand() ); |
438 | |
439 | // Use the first runs as a check. This gives a chance for first- |
440 | // time static initialization to not interfere in the timings. |
441 | uint32_t const basic_result = basic_crc32( buffer: ran_data, byte_count: sizeof(ran_data) ); |
442 | uint32_t const optimal_result = optimal_crc32( buffer: ran_data, byte_count: sizeof(ran_data) ); |
443 | uint32_t const quick_result = quick_crc32( buffer: ran_data, byte_count: sizeof(ran_data) ); |
444 | |
445 | BOOST_TEST_EQ( basic_result, optimal_result ); |
446 | BOOST_TEST_EQ( optimal_result, quick_result ); |
447 | BOOST_TEST_EQ( quick_result, basic_result ); |
448 | |
449 | // Run trials |
450 | double const basic_rate = time_trial( name: "Boost-Basic" , crc_func: basic_crc32, |
451 | expected: basic_result, data: ran_data, length: sizeof(ran_data) ); |
452 | double const optimal_rate = time_trial( name: "Boost-Optimal" , crc_func: optimal_crc32, |
453 | expected: optimal_result, data: ran_data, length: sizeof(ran_data) ); |
454 | double const quick_rate = time_trial( name: "Reference" , crc_func: quick_crc32, |
455 | expected: quick_result, data: ran_data, length: sizeof(ran_data) ); |
456 | |
457 | // Report results |
458 | cout << "\tThe optimal Boost version has " << optimal_rate / quick_rate * |
459 | 100.0 << "% the speed of the reference version.\n" ; |
460 | cout << "\tThe basic Boost version has " << basic_rate / quick_rate * 100.0 |
461 | << "% the speed of the reference version.\n" ; |
462 | cout << "\tThe basic Boost version has " << basic_rate / optimal_rate * |
463 | 100.0 << "% the speed of the optimal Boost version." |
464 | << endl; |
465 | } |
466 | |
467 | |
468 | // Reformat an integer to the big-endian storage format |
469 | boost::uint32_t |
470 | native_to_big |
471 | ( |
472 | boost::uint32_t x |
473 | ) |
474 | { |
475 | boost::uint32_t temp; |
476 | unsigned char * tp = reinterpret_cast<unsigned char *>( &temp ); |
477 | |
478 | for ( std::size_t i = sizeof(x) ; i > 0 ; --i ) |
479 | { |
480 | tp[ i - 1 ] = static_cast<unsigned char>( x ); |
481 | x >>= CHAR_BIT; |
482 | } |
483 | |
484 | return temp; |
485 | } |
486 | |
487 | // Restore an integer from the big-endian storage format |
488 | boost::uint32_t |
489 | big_to_native |
490 | ( |
491 | boost::uint32_t x |
492 | ) |
493 | { |
494 | boost::uint32_t temp = 0; |
495 | unsigned char * xp = reinterpret_cast<unsigned char *>( &x ); |
496 | |
497 | for ( std::size_t i = 0 ; i < sizeof(x) ; ++i ) |
498 | { |
499 | temp <<= CHAR_BIT; |
500 | temp |= xp[ i ]; |
501 | } |
502 | |
503 | return temp; |
504 | } |
505 | |
506 | // Run tests on using CRCs on augmented messages |
507 | void |
508 | augmented_tests |
509 | ( |
510 | ) |
511 | { |
512 | #define PRIVATE_ACRC_FUNC boost::augmented_crc<32, 0x04C11DB7> |
513 | |
514 | using std::size_t; |
515 | PRIVATE_DECLARE_BOOST( uint32_t ); |
516 | |
517 | std::cout << "Doing CRC-augmented message tests." << std::endl; |
518 | |
519 | // Create a random block of data, with space for a CRC. |
520 | uint32_t ran_data[ 257 ]; |
521 | size_t const ran_length = sizeof(ran_data) / sizeof(ran_data[0]); |
522 | size_t const data_length = ran_length - 1; |
523 | |
524 | std::generate_n( first: ran_data, n: data_length, gen: boost::minstd_rand() ); |
525 | |
526 | // When creating a CRC for an augmented message, use |
527 | // zeros in the appended CRC spot for the first run. |
528 | uint32_t & ran_crc = ran_data[ data_length ]; |
529 | |
530 | ran_crc = 0; |
531 | |
532 | // Compute the CRC with augmented-CRC computing function |
533 | typedef boost::uint_t<32>::fast return_type; |
534 | |
535 | ran_crc = PRIVATE_ACRC_FUNC( buffer: ran_data, byte_count: sizeof(ran_data) ); |
536 | |
537 | // With the appended CRC set, running the checksum again should get zero. |
538 | // NOTE: CRC algorithm assumes numbers are in big-endian format |
539 | ran_crc = native_to_big( x: ran_crc ); |
540 | |
541 | uint32_t ran_crc_check = PRIVATE_ACRC_FUNC( buffer: ran_data, byte_count: sizeof(ran_data) ); |
542 | |
543 | BOOST_TEST_EQ( 0, ran_crc_check ); |
544 | |
545 | // Compare that result with other CRC computing functions |
546 | // and classes, which don't accept augmented messages. |
547 | typedef boost::crc_optimal<32, 0x04C11DB7> fast_crc_type; |
548 | typedef boost::crc_basic<32> slow_crc_type; |
549 | |
550 | fast_crc_type fast_tester; |
551 | slow_crc_type slow_tester( 0x04C11DB7 ); |
552 | size_t const data_size = data_length * sizeof(ran_data[0]); |
553 | uint32_t const func_tester = boost::crc<32, 0x04C11DB7, 0, 0, false, |
554 | false>( buffer: ran_data, byte_count: data_size ); |
555 | |
556 | fast_tester.process_bytes( buffer: ran_data, byte_count: data_size ); |
557 | slow_tester.process_bytes( buffer: ran_data, byte_count: data_size ); |
558 | BOOST_TEST_EQ( fast_tester.checksum(), slow_tester.checksum() ); |
559 | ran_crc = big_to_native( x: ran_crc ); |
560 | BOOST_TEST_EQ( fast_tester.checksum(), ran_crc ); |
561 | BOOST_TEST_EQ( func_tester, ran_crc ); |
562 | |
563 | // Do a single-bit error test |
564 | ran_crc = native_to_big( x: ran_crc ); |
565 | ran_data[ ran_data[0] % ran_length ] ^= ( 1 << (ran_data[1] % 32) ); |
566 | ran_crc_check = PRIVATE_ACRC_FUNC( buffer: ran_data, byte_count: sizeof(ran_data) ); |
567 | BOOST_TEST_NE( 0, ran_crc_check ); |
568 | |
569 | // Run a version of these tests with a nonzero initial remainder. |
570 | uint32_t const init_rem = ran_data[ ran_data[2] % ran_length ]; |
571 | |
572 | ran_crc = 0; |
573 | ran_crc = PRIVATE_ACRC_FUNC( buffer: ran_data, byte_count: sizeof(ran_data), initial_remainder: init_rem ); |
574 | |
575 | // Have some fun by processing data in two steps. |
576 | size_t const mid_index = ran_length / 2; |
577 | |
578 | ran_crc = native_to_big( x: ran_crc ); |
579 | ran_crc_check = PRIVATE_ACRC_FUNC( buffer: ran_data, byte_count: mid_index |
580 | * sizeof(ran_data[0]), initial_remainder: init_rem ); |
581 | ran_crc_check = PRIVATE_ACRC_FUNC( buffer: &ran_data[mid_index], byte_count: sizeof(ran_data) |
582 | - mid_index * sizeof(ran_data[0]), initial_remainder: ran_crc_check ); |
583 | BOOST_TEST_EQ( 0, ran_crc_check ); |
584 | |
585 | // This substep translates an augmented-CRC initial |
586 | // remainder to an unaugmented-CRC initial remainder. |
587 | uint32_t const zero = 0; |
588 | uint32_t const new_init_rem = PRIVATE_ACRC_FUNC( buffer: &zero, byte_count: sizeof(zero), |
589 | initial_remainder: init_rem ); |
590 | slow_crc_type slow_tester2( 0x04C11DB7, new_init_rem ); |
591 | |
592 | slow_tester2.process_bytes( buffer: ran_data, byte_count: data_size ); |
593 | ran_crc = big_to_native( x: ran_crc ); |
594 | BOOST_TEST_EQ( slow_tester2.checksum(), ran_crc ); |
595 | |
596 | // Redo single-bit error test |
597 | ran_data[ ran_data[3] % ran_length ] ^= ( 1 << (ran_data[4] % 32) ); |
598 | ran_crc_check = PRIVATE_ACRC_FUNC( buffer: ran_data, byte_count: sizeof(ran_data), initial_remainder: init_rem ); |
599 | BOOST_TEST_NE( 0, ran_crc_check ); |
600 | |
601 | #undef PRIVATE_ACRC_FUNC |
602 | } |
603 | |
604 | |
605 | // Run tests on CRCs below a byte in size (here, 3 bits) |
606 | void |
607 | small_crc_test1 |
608 | ( |
609 | ) |
610 | { |
611 | std::cout << "Doing short-CRC (3-bit augmented) message tests." |
612 | << std::endl; |
613 | |
614 | // The CRC standard is a SDH/SONET Low Order LCAS control word with CRC-3 |
615 | // taken from ITU-T G.707 (12/03) XIII.2. |
616 | |
617 | // Four samples, each four bytes; should all have a CRC of zero |
618 | unsigned char const samples[4][4] |
619 | = { |
620 | { 0x3A, 0xC4, 0x08, 0x06 }, |
621 | { 0x42, 0xC5, 0x0A, 0x41 }, |
622 | { 0x4A, 0xC5, 0x08, 0x22 }, |
623 | { 0x52, 0xC4, 0x08, 0x05 } |
624 | }; |
625 | |
626 | // Basic computer |
627 | boost::crc_basic<3> tester1( 0x03 ); |
628 | |
629 | tester1.process_bytes( buffer: samples[0], byte_count: 4 ); |
630 | BOOST_TEST_EQ( tester1.checksum(), 0 ); |
631 | |
632 | tester1.reset(); |
633 | tester1.process_bytes( buffer: samples[1], byte_count: 4 ); |
634 | BOOST_TEST_EQ( tester1.checksum(), 0 ); |
635 | |
636 | tester1.reset(); |
637 | tester1.process_bytes( buffer: samples[2], byte_count: 4 ); |
638 | BOOST_TEST_EQ( tester1.checksum(), 0 ); |
639 | |
640 | tester1.reset(); |
641 | tester1.process_bytes( buffer: samples[3], byte_count: 4 ); |
642 | BOOST_TEST_EQ( tester1.checksum(), 0 ); |
643 | |
644 | // Optimal computer |
645 | #define PRIVATE_CRC_FUNC boost::crc<3, 0x03, 0, 0, false, false> |
646 | #define PRIVATE_ACRC_FUNC boost::augmented_crc<3, 0x03> |
647 | |
648 | BOOST_TEST_EQ( 0, PRIVATE_CRC_FUNC(samples[0], 4) ); |
649 | BOOST_TEST_EQ( 0, PRIVATE_CRC_FUNC(samples[1], 4) ); |
650 | BOOST_TEST_EQ( 0, PRIVATE_CRC_FUNC(samples[2], 4) ); |
651 | BOOST_TEST_EQ( 0, PRIVATE_CRC_FUNC(samples[3], 4) ); |
652 | |
653 | // maybe the fix to CRC functions needs to be applied to augmented CRCs? |
654 | |
655 | #undef PRIVATE_ACRC_FUNC |
656 | #undef PRIVATE_CRC_FUNC |
657 | } |
658 | |
659 | // Run tests on CRCs below a byte in size (here, 7 bits) |
660 | void |
661 | small_crc_test2 |
662 | ( |
663 | ) |
664 | { |
665 | std::cout << "Doing short-CRC (7-bit augmented) message tests." |
666 | << std::endl; |
667 | |
668 | // The CRC standard is a SDH/SONET J0/J1/J2/N1/N2/TR TTI (trace message) |
669 | // with CRC-7, o.a. ITU-T G.707 Annex B, G.832 Annex A. |
670 | |
671 | // Two samples, each sixteen bytes |
672 | // Sample 1 is '\x80' + ASCII("123456789ABCDEF") |
673 | // Sample 2 is '\x80' + ASCII("TTI UNAVAILABLE") |
674 | unsigned char const samples[2][16] |
675 | = { |
676 | { 0x80, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, |
677 | 0x42, 0x43, 0x44, 0x45, 0x46 }, |
678 | { 0x80, 0x54, 0x54, 0x49, 0x20, 0x55, 0x4E, 0x41, 0x56, 0x41, 0x49, |
679 | 0x4C, 0x41, 0x42, 0x4C, 0x45 } |
680 | }; |
681 | unsigned const results[2] = { 0x62, 0x23 }; |
682 | |
683 | // Basic computer |
684 | boost::crc_basic<7> tester1( 0x09 ); |
685 | |
686 | tester1.process_bytes( buffer: samples[0], byte_count: 16 ); |
687 | BOOST_TEST_EQ( tester1.checksum(), results[0] ); |
688 | |
689 | tester1.reset(); |
690 | tester1.process_bytes( buffer: samples[1], byte_count: 16 ); |
691 | BOOST_TEST_EQ( tester1.checksum(), results[1] ); |
692 | |
693 | // Optimal computer |
694 | #define PRIVATE_CRC_FUNC boost::crc<7, 0x09, 0, 0, false, false> |
695 | #define PRIVATE_ACRC_FUNC boost::augmented_crc<7, 0x09> |
696 | |
697 | BOOST_TEST_EQ( results[0], PRIVATE_CRC_FUNC(samples[0], 16) ); |
698 | BOOST_TEST_EQ( results[1], PRIVATE_CRC_FUNC(samples[1], 16) ); |
699 | |
700 | // maybe the fix to CRC functions needs to be applied to augmented CRCs? |
701 | |
702 | #undef PRIVATE_ACRC_FUNC |
703 | #undef PRIVATE_CRC_FUNC |
704 | } |
705 | |
706 | |
707 | #ifndef BOOST_MSVC |
708 | // Explicit template instantiations |
709 | // (needed to fix a link error in Metrowerks CodeWarrior Pro 5.3) |
710 | template class crc_tester<16, 0x1021, 0xFFFF, 0, false, false>; |
711 | template class crc_tester<16, 0x8005, 0, 0, true, true>; |
712 | template class crc_tester<32, 0x04C11DB7, 0xFFFFFFFF, 0xFFFFFFFF, true, true>; |
713 | #endif |
714 | |
715 | // Main testing function |
716 | int main() |
717 | { |
718 | using std::cout; |
719 | using std::endl; |
720 | |
721 | // Run simulations on some CRC types |
722 | typedef crc_tester<16, 0x1021, 0xFFFF, 0, false, false> crc_ccitt_tester; |
723 | typedef crc_tester<16, 0x8005, 0, 0, true, true> crc_16_tester; |
724 | typedef crc_tester<32, 0x04C11DB7, 0xFFFFFFFF, 0xFFFFFFFF, true, true> |
725 | crc_32_tester; |
726 | |
727 | crc_ccitt_tester::master_test( test_name: "CRC-CCITT" , expected: std_crc_ccitt_result ); |
728 | crc_16_tester::master_test( test_name: "CRC-16" , expected: std_crc_16_result ); |
729 | crc_32_tester::master_test( test_name: "CRC-32" , expected: std_crc_32_result ); |
730 | |
731 | // Run a timing comparison test |
732 | timing_test(); |
733 | |
734 | // Test using augmented messages |
735 | augmented_tests(); |
736 | |
737 | // Test with CRC types smaller than a byte |
738 | small_crc_test1(); |
739 | small_crc_test2(); |
740 | |
741 | // Try a CRC based on the (x + 1) polynominal, which is a factor in |
742 | // many real-life polynominals and doesn't fit evenly in a byte. |
743 | cout << "Doing one-bit polynominal CRC test." << endl; |
744 | boost::crc_basic<1> crc_1( 1 ); |
745 | crc_1.process_bytes( buffer: std_data, byte_count: std_data_len ); |
746 | BOOST_TEST_EQ( crc_1.checksum(), 1 ); |
747 | |
748 | // Test the function object interface |
749 | cout << "Doing functional object interface test." << endl; |
750 | boost::crc_optimal<16, 0x8005, 0, 0, true, true> crc_16; |
751 | crc_16 = std::for_each( first: std_data, last: std_data + std_data_len, f: crc_16 ); |
752 | BOOST_TEST_EQ( crc_16(), std_crc_16_result ); |
753 | |
754 | return boost::report_errors(); |
755 | } |
756 | |