File: crc_test.cpp

package info (click to toggle)
boost 1.27.0-3
  • links: PTS
  • area: main
  • in suites: woody
  • size: 19,908 kB
  • ctags: 26,546
  • sloc: cpp: 122,225; ansic: 10,956; python: 4,412; sh: 855; yacc: 803; makefile: 257; perl: 165; lex: 90; csh: 6
file content (650 lines) | stat: -rw-r--r-- 21,486 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
//  Boost CRC test program file  ---------------------------------------------//

//  (C) Copyright Daryle Walker 2001.  Permission to copy, use, modify, sell
//  and distribute this software is granted provided this copyright notice
//  appears in all copies.  This software is provided "as is" without express or
//  implied warranty, and with no claim as to its suitability for any purpose.

//  Revision History
//  14 May 2001  Initial version (Daryle Walker)


// Use the full Boost test tools in this file
#define  BOOST_INCLUDE_MAIN
#include <boost/test/test_tools.hpp>

#include <boost/config.hpp>                      // for BOOST_MSVC, etc.
#include <boost/crc.hpp>                         // for boost::crc_basic, etc.
#include <boost/cstdint.hpp>                     // for boost::uint16_t, etc.
#include <boost/cstdlib.hpp>                     // for boost::exit_success
#include <boost/integer.hpp>                     // for boost::uint_t
#include <boost/random/linear_congruential.hpp>  // for boost::minstd_rand
#include <boost/timer.hpp>                       // for boost::timer

#include <algorithm>  // for std::for_each, std::generate_n, std::count
#include <climits>    // for CHAR_BIT
#include <cstddef>    // for std::size_t
#include <iostream>   // for std::cout (std::ostream and std::endl indirectly)


#if CHAR_BIT != 8
#error The expected results assume an eight-bit byte.
#endif

#ifndef BOOST_NO_DEPENDENT_TYPES_IN_TEMPLATE_VALUE_PARAMETERS
#define CRC_PARM_TYPE  typename boost::uint_t<Bits>::fast
#else
#define CRC_PARM_TYPE  unsigned long
#endif

#if !defined(BOOST_MSVC) && !defined(__GNUC__)
#define PRIVATE_DECLARE_BOOST( TypeName )  using boost:: TypeName
#else
#define PRIVATE_DECLARE_BOOST( TypeName )  typedef boost:: TypeName  TypeName
#endif


// Types
template < std::size_t Bits, CRC_PARM_TYPE TrPo, CRC_PARM_TYPE InRe,
           CRC_PARM_TYPE FiXo, bool ReIn, bool ReRe >
class crc_tester
{
public:
    // All the following were separate function templates, but they have
    // been moved to class-static member functions of a class template
    // because MS VC++ 6 can't handle function templates that can't
    // deduce all their template arguments from their function arguments.

    typedef typename boost::uint_t<Bits>::fast  value_type;

    static  void  master_test( char const *test_name, value_type expected );

private:
    typedef boost::crc_optimal<Bits, TrPo, InRe, FiXo, ReIn, ReRe>
      optimal_crc_type;
    typedef boost::crc_basic<Bits>  basic_crc_type;

    static  void  compute_test( value_type expected );
    static  void  interrupt_test( value_type expected );
    static  void  error_test();

};  // crc_tester

// Global data
unsigned char const  std_data[] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
                      0x38, 0x39 };
std::size_t const    std_data_len = sizeof( std_data ) / sizeof( std_data[0] );

boost::uint16_t const  std_crc_ccitt_result = 0x29B1;
boost::uint16_t const  std_crc_16_result = 0xBB3D;
boost::uint32_t const  std_crc_32_result = 0xCBF43926;

// Function prototypes
void             timing_test();
boost::uint32_t  basic_crc32( void const *buffer, std::size_t byte_count );
boost::uint32_t  optimal_crc32( void const *buffer, std::size_t byte_count );
boost::uint32_t  quick_crc32( void const *buffer, std::size_t byte_count );
boost::uint32_t  quick_reflect( boost::uint32_t value, std::size_t bits );
double           time_trial( char const *name,
 boost::uint32_t (*crc_func)(void const *, std::size_t),
 boost::uint32_t expected, void const *data, std::size_t length );

void             augmented_tests();
boost::uint32_t  native_to_big( boost::uint32_t x );
boost::uint32_t  big_to_native( boost::uint32_t x );


// Macro to compact code
#define PRIVATE_TESTER_NAME  crc_tester<Bits, TrPo, InRe, FiXo, ReIn, ReRe>

// Run a test on slow and fast CRC computers and function
template < std::size_t Bits, CRC_PARM_TYPE TrPo, CRC_PARM_TYPE InRe,
           CRC_PARM_TYPE FiXo, bool ReIn, bool ReRe >
void
PRIVATE_TESTER_NAME::compute_test
(
    typename PRIVATE_TESTER_NAME::value_type  expected
)
{
    std::cout << "\tDoing computation tests." << std::endl;

    optimal_crc_type  fast_crc;
    basic_crc_type    slow_crc( TrPo, InRe, FiXo, ReIn, ReRe );
    value_type const  func_result = boost::crc<Bits, TrPo, InRe, FiXo, ReIn,
     ReRe>( std_data, std_data_len );

    fast_crc.process_bytes( std_data, std_data_len );
    slow_crc.process_bytes( std_data, std_data_len );
    BOOST_TEST( fast_crc.checksum() == expected );
    BOOST_TEST( slow_crc.checksum() == expected );
    BOOST_TEST( func_result == expected );
}

// Run a test in two runs, and check all the inspectors
template < std::size_t Bits, CRC_PARM_TYPE TrPo, CRC_PARM_TYPE InRe,
           CRC_PARM_TYPE FiXo, bool ReIn, bool ReRe >
void
PRIVATE_TESTER_NAME::interrupt_test
(
    typename PRIVATE_TESTER_NAME::value_type  expected
)
{
    std::cout << "\tDoing interrupt tests." << std::endl;

    // Process the first half of the data (also test accessors)
    optimal_crc_type  fast_crc1;
    basic_crc_type    slow_crc1( fast_crc1.get_truncated_polynominal(),
     fast_crc1.get_initial_remainder(), fast_crc1.get_final_xor_value(),
     fast_crc1.get_reflect_input(), fast_crc1.get_reflect_remainder() );

    BOOST_TEST( fast_crc1.get_interim_remainder() ==
     slow_crc1.get_initial_remainder() );

    std::size_t const            mid_way = std_data_len / 2;
    unsigned char const * const  std_data_end = std_data + std_data_len;

    fast_crc1.process_bytes( std_data, mid_way );
    slow_crc1.process_bytes( std_data, mid_way );
    BOOST_TEST( fast_crc1.checksum() == slow_crc1.checksum() );

    // Process the second half of the data (also test accessors)
    boost::crc_optimal<optimal_crc_type::bit_count,
     optimal_crc_type::truncated_polynominal, optimal_crc_type::initial_remainder,
     optimal_crc_type::final_xor_value, optimal_crc_type::reflect_input,
     optimal_crc_type::reflect_remainder>
      fast_crc2( fast_crc1.get_interim_remainder() );
    boost::crc_basic<basic_crc_type::bit_count>  slow_crc2(
     slow_crc1.get_truncated_polynominal(), slow_crc1.get_interim_remainder(),
     slow_crc1.get_final_xor_value(), slow_crc1.get_reflect_input(),
     slow_crc1.get_reflect_remainder() );

    fast_crc2.process_block( std_data + mid_way, std_data_end );
    slow_crc2.process_block( std_data + mid_way, std_data_end );
    BOOST_TEST( fast_crc2.checksum() == slow_crc2.checksum() );
    BOOST_TEST( fast_crc2.checksum() == expected );
    BOOST_TEST( slow_crc2.checksum() == expected );
}

// Run a test to see if a single-bit error is detected
template < std::size_t Bits, CRC_PARM_TYPE TrPo, CRC_PARM_TYPE InRe,
           CRC_PARM_TYPE FiXo, bool ReIn, bool ReRe >
void
PRIVATE_TESTER_NAME::error_test
(
)
{
    PRIVATE_DECLARE_BOOST( uint32_t );

    // A single-bit error is ensured to be detected if the polynominal
    // has at least two bits set.  The highest bit is what is removed
    // to give the truncated polynominal, and it is always set.  This
    // means that the truncated polynominal needs at least one of its
    // bits set, which implies that it cannot be zero.
    if ( !(TrPo & boost::detail::mask_uint_t<Bits>::sig_bits_fast) )
    {
        BOOST_CRITICAL_ERROR( "truncated CRC polymonial is zero" );
    }

    std::cout << "\tDoing error tests." << std::endl;

    // Create a random block of data
    uint32_t           ran_data[ 256 ];
    std::size_t const  ran_length = sizeof(ran_data) / sizeof(ran_data[0]);

    std::generate_n( ran_data, ran_length, boost::minstd_rand() );

    // Create computers and compute the checksum of the data
    optimal_crc_type  fast_tester;
    basic_crc_type    slow_tester( TrPo, InRe, FiXo, ReIn, ReRe );

    fast_tester.process_bytes( ran_data, sizeof(ran_data) );
    slow_tester.process_bytes( ran_data, sizeof(ran_data) );

    uint32_t const  fast_checksum = fast_tester.checksum();
    uint32_t const  slow_checksum = slow_tester.checksum();

    BOOST_TEST( fast_checksum == slow_checksum );

    // Do the checksum again (and test resetting ability)
    fast_tester.reset();
    slow_tester.reset( InRe );
    fast_tester.process_bytes( ran_data, sizeof(ran_data) );
    slow_tester.process_bytes( ran_data, sizeof(ran_data) );
    BOOST_TEST( fast_tester.checksum() == slow_tester.checksum() );
    BOOST_TEST( fast_tester.checksum() == fast_checksum );
    BOOST_TEST( slow_tester.checksum() == slow_checksum );

    // Produce a single-bit error
    ran_data[ ran_data[0] % ran_length ] ^= ( 1 << (ran_data[1] % 32) );

    // Compute the checksum of the errorenous data
    // (and continue testing resetting ability)
    fast_tester.reset( InRe );
    slow_tester.reset();
    fast_tester.process_bytes( ran_data, sizeof(ran_data) );
    slow_tester.process_bytes( ran_data, sizeof(ran_data) );
    BOOST_TEST( fast_tester.checksum() == slow_tester.checksum() );
    BOOST_TEST( fast_tester.checksum() != fast_checksum );
    BOOST_TEST( slow_tester.checksum() != slow_checksum );
}

// Run the other CRC object tests
template < std::size_t Bits, CRC_PARM_TYPE TrPo, CRC_PARM_TYPE InRe,
           CRC_PARM_TYPE FiXo, bool ReIn, bool ReRe >
void
PRIVATE_TESTER_NAME::master_test
(
    char const *                              test_name,
    typename PRIVATE_TESTER_NAME::value_type  expected
)
{
    std::cout << "Doing test suite for " << test_name << '.' << std::endl;
    compute_test( expected );
    interrupt_test( expected );
    error_test();
}

// Undo limited macros
#undef PRIVATE_TESTER_NAME


// A CRC-32 computer based on crc_basic, for timing
boost::uint32_t
basic_crc32
(
    void const *  buffer,
    std::size_t   byte_count
)
{
    static  boost::crc_basic<32>  computer( 0x04C11DB7, 0xFFFFFFFF, 0xFFFFFFFF,
     true, true );

    computer.reset();
    computer.process_bytes( buffer, byte_count );
    return computer.checksum();
}

// A CRC-32 computer based on crc_optimal, for timing
inline
boost::uint32_t
optimal_crc32
(
    void const *  buffer,
    std::size_t   byte_count
)
{
    static  boost::crc_32_type  computer;

    computer.reset();
    computer.process_bytes( buffer, byte_count );
    return computer.checksum();
}

// Reflect the lower "bits" bits of a "value"
boost::uint32_t
quick_reflect
(
    boost::uint32_t  value,
    std::size_t      bits
)
{
    boost::uint32_t  reflection = 0;
    for ( std::size_t i = 0 ; i < bits ; ++i )
    {
        if ( value & (1u << i) )
        {
            reflection |= 1 << ( bits - 1 - i );
        }
    }

    return reflection;
}

// A customized CRC-32 computer, for timing
boost::uint32_t
quick_crc32
(
    void const *  buffer,
    std::size_t   byte_count
)
{
    PRIVATE_DECLARE_BOOST( uint32_t );
    typedef unsigned char  byte_type;

    // Compute the CRC table (first run only)
    static  bool      did_init = false;
    static  uint32_t  crc_table[ 1ul << CHAR_BIT ];
    if ( !did_init )
    {
        uint32_t const  value_high_bit = static_cast<uint32_t>(1) << 31u;

        byte_type  dividend = 0;
        do
        {
            uint32_t  remainder = 0;
            for ( byte_type mask = 1u << (CHAR_BIT - 1u) ; mask ; mask >>= 1 )
            {
                if ( dividend & mask )
                {
                    remainder ^= value_high_bit;
                }

                if ( remainder & value_high_bit )
                {
                    remainder <<= 1;
                    remainder ^= 0x04C11DB7u;
                }
                else
                {
                    remainder <<= 1;
                }
            }

            crc_table[ quick_reflect(dividend, CHAR_BIT) ]
             = quick_reflect( remainder, 32 );
        }
        while ( ++dividend );

        did_init = true;
    }

    // Compute the CRC of the data
    uint32_t  rem = 0xFFFFFFFF;

    byte_type const * const  b_begin = static_cast<byte_type const *>( buffer );
    byte_type const * const  b_end = b_begin + byte_count;
    for ( byte_type const *p = b_begin ; p < b_end ; ++p )
    {
        byte_type const  byte_index = *p ^ rem;
        rem >>= CHAR_BIT;
        rem ^= crc_table[ byte_index ];
    }

    return ~rem;
}

// Run an individual timing trial
double
time_trial
(
    char const *       name,
    boost::uint32_t  (*crc_func)(void const *, std::size_t),
    boost::uint32_t    expected,
    void const *       data,
    std::size_t        length
)
{
    PRIVATE_DECLARE_BOOST( uint32_t );
    using std::cout;

    // Limits of a trial
    static uint32_t const  max_count = 1L << 16;  // ~square-root of max
    static double const    max_time = 3.14159;    // easy as pi(e)

    // Mark the trial
    cout << '\t' << name << " CRC-32: ";

    // Trial loop
    uint32_t      trial_count = 0, wrong_count = 0;
    double        elapsed_time = 0.0;
    boost::timer  t;

    do
    {
        uint32_t const  scratch = (*crc_func)( data, length );

        if ( scratch != expected )
        {
            ++wrong_count;
        }
        elapsed_time = t.elapsed();
        ++trial_count;
    } while ( (trial_count < max_count) && (elapsed_time < max_time) );

    if ( wrong_count )
    {
        BOOST_ERROR( "at least one time trial didn't match expected" );
    }

    // Report results
    double const  rate = trial_count / elapsed_time;

    cout << trial_count << " runs, " << elapsed_time << " s, " << rate
     << " run/s" << std::endl;
    return rate;
}

// Time runs of Boost CRCs vs. a customized CRC function
void
timing_test
(
)
{
    PRIVATE_DECLARE_BOOST( uint32_t );
    using std::cout;
    using std::endl;

    cout << "Doing timing tests." << endl;

    // Create a random block of data
    boost::int32_t     ran_data[ 256 ];
    std::size_t const  ran_length = sizeof(ran_data) / sizeof(ran_data[0]);

    std::generate_n( ran_data, ran_length, boost::minstd_rand() );

    // Use the first runs as a check.  This gives a chance for first-
    // time static initialization to not interfere in the timings.
    uint32_t const  basic_result = basic_crc32( ran_data, sizeof(ran_data) );
    uint32_t const  optimal_result = optimal_crc32( ran_data, sizeof(ran_data) );
    uint32_t const  quick_result = quick_crc32( ran_data, sizeof(ran_data) );

    BOOST_TEST( basic_result == optimal_result );
    BOOST_TEST( optimal_result == quick_result );
    BOOST_TEST( quick_result == basic_result );

    // Run trials
    double const  basic_rate = time_trial( "Boost-Basic", basic_crc32,
     basic_result, ran_data, sizeof(ran_data) );
    double const  optimal_rate = time_trial( "Boost-Optimal", optimal_crc32,
     optimal_result, ran_data, sizeof(ran_data) );
    double const  quick_rate = time_trial( "Reference", quick_crc32,
     quick_result, ran_data, sizeof(ran_data) );

    // Report results
    cout << "\tThe optimal Boost version is " << (quick_rate - optimal_rate)
     / quick_rate * 100.0 << "% slower than the reference version.\n";
    cout << "\tThe basic Boost version is " << (quick_rate - basic_rate)
     / quick_rate * 100.0 << "% slower than the reference version.\n";
    cout << "\tThe basic Boost version is " << (optimal_rate - basic_rate)
     / optimal_rate * 100.0 << "% slower than the optimal Boost version."
     << endl;
}


// Reformat an integer to the big-endian storage format
boost::uint32_t
native_to_big
(
    boost::uint32_t  x
)
{
    boost::uint32_t  temp;
    unsigned char *  tp = reinterpret_cast<unsigned char *>( &temp );

    for ( std::size_t i = sizeof(x) ; i > 0 ; --i )
    {
        tp[ i - 1 ] = static_cast<unsigned char>( x );
        x >>= CHAR_BIT;
    }

    return temp;
}

// Restore an integer from the big-endian storage format
boost::uint32_t
big_to_native
(
    boost::uint32_t  x
)
{
    boost::uint32_t  temp = 0;
    unsigned char *  xp = reinterpret_cast<unsigned char *>( &x );

    for ( std::size_t i = 0 ; i < sizeof(x) ; ++i )
    {
        temp <<= CHAR_BIT;
        temp |= xp[ i ];
    }

    return temp;
}

// Run tests on using CRCs on augmented messages
void
augmented_tests
(
)
{
    #define PRIVATE_ACRC_FUNC  boost::augmented_crc<32, 0x04C11DB7>

    using std::size_t;
    PRIVATE_DECLARE_BOOST( uint32_t );

    std::cout << "Doing CRC-augmented message tests." << std::endl;

    // Create a random block of data, with space for a CRC.
    uint32_t      ran_data[ 257 ];
    size_t const  ran_length = sizeof(ran_data) / sizeof(ran_data[0]);
    size_t const  data_length = ran_length - 1;

    std::generate_n( ran_data, data_length, boost::minstd_rand() );

    // When creating a CRC for an augmented message, use
    // zeros in the appended CRC spot for the first run.
    uint32_t &  ran_crc = ran_data[ data_length ];

    ran_crc = 0;

    // Compute the CRC with augmented-CRC computing function
    typedef boost::uint_t<32>::fast  return_type;

    ran_crc = PRIVATE_ACRC_FUNC( ran_data, sizeof(ran_data) );

    // With the appended CRC set, running the checksum again should get zero.
    // NOTE: CRC algorithm assumes numbers are in big-endian format
    ran_crc = native_to_big( ran_crc );

    uint32_t  ran_crc_check = PRIVATE_ACRC_FUNC( ran_data, sizeof(ran_data) );

    BOOST_TEST( 0 == ran_crc_check );

    // Compare that result with other CRC computing functions
    // and classes, which don't accept augmented messages.
    typedef boost::crc_optimal<32, 0x04C11DB7>  fast_crc_type;
    typedef boost::crc_basic<32>                slow_crc_type;

    fast_crc_type   fast_tester;
    slow_crc_type   slow_tester( 0x04C11DB7 );
    size_t const    data_size = data_length * sizeof(ran_data[0]);
    uint32_t const  func_tester = boost::crc<32, 0x04C11DB7, 0, 0, false,
     false>( ran_data, data_size );

    fast_tester.process_bytes( ran_data, data_size );
    slow_tester.process_bytes( ran_data, data_size );
    BOOST_TEST( fast_tester.checksum() == slow_tester.checksum() );
    ran_crc = big_to_native( ran_crc );
    BOOST_TEST( fast_tester.checksum() == ran_crc );
    BOOST_TEST( func_tester == ran_crc );

    // Do a single-bit error test
    ran_crc = native_to_big( ran_crc );
    ran_data[ ran_data[0] % ran_length ] ^= ( 1 << (ran_data[1] % 32) );
    ran_crc_check = PRIVATE_ACRC_FUNC( ran_data, sizeof(ran_data) );
    BOOST_TEST( 0 != ran_crc_check );

    // Run a version of these tests with a nonzero initial remainder.
    uint32_t const  init_rem = ran_data[ ran_data[2] % ran_length ];

    ran_crc = 0;
    ran_crc = PRIVATE_ACRC_FUNC( ran_data, sizeof(ran_data), init_rem );

    // Have some fun by processing data in two steps.
    size_t const  mid_index = ran_length / 2;

    ran_crc = native_to_big( ran_crc );
    ran_crc_check = PRIVATE_ACRC_FUNC( ran_data, mid_index
     * sizeof(ran_data[0]), init_rem );
    ran_crc_check = PRIVATE_ACRC_FUNC( &ran_data[mid_index], sizeof(ran_data)
     - mid_index * sizeof(ran_data[0]), ran_crc_check );
    BOOST_TEST( 0 == ran_crc_check );

    // This substep translates an augmented-CRC initial
    // remainder to an unaugmented-CRC initial remainder.
    uint32_t const  zero = 0;
    uint32_t const  new_init_rem = PRIVATE_ACRC_FUNC( &zero, sizeof(zero),
     init_rem );
    slow_crc_type   slow_tester2( 0x04C11DB7, new_init_rem );

    slow_tester2.process_bytes( ran_data, data_size );
    ran_crc = big_to_native( ran_crc );
    BOOST_TEST( slow_tester2.checksum() == ran_crc );

    // Redo single-bit error test
    ran_data[ ran_data[3] % ran_length ] ^= ( 1 << (ran_data[4] % 32) );
    ran_crc_check = PRIVATE_ACRC_FUNC( ran_data, sizeof(ran_data), init_rem );
    BOOST_TEST( 0 != ran_crc_check );

    #undef PRIVATE_ACRC_FUNC
}


#ifndef BOOST_MSVC
// Explicit template instantiations
// (needed to fix a link error in Metrowerks CodeWarrior Pro 5.3)
template class crc_tester<16, 0x1021, 0xFFFF, 0, false, false>;
template class crc_tester<16, 0x8005, 0, 0, true, true>;
template class crc_tester<32, 0x04C11DB7, 0xFFFFFFFF, 0xFFFFFFFF, true, true>;
#endif

// Main testing function
int
test_main
(
    int         ,   // "argc" is unused
    char *      []  // "argv" is unused
)
{
    using std::cout;
    using std::endl;

    // Run simulations on some CRC types
    typedef crc_tester<16, 0x1021, 0xFFFF, 0, false, false>  crc_ccitt_tester;
    typedef crc_tester<16, 0x8005, 0, 0, true, true>         crc_16_tester;
    typedef crc_tester<32, 0x04C11DB7, 0xFFFFFFFF, 0xFFFFFFFF, true, true>
      crc_32_tester;

    crc_ccitt_tester::master_test( "CRC-CCITT", std_crc_ccitt_result );
    crc_16_tester::master_test( "CRC-16", std_crc_16_result );
    crc_32_tester::master_test( "CRC-32", std_crc_32_result );

    // Run a timing comparison test
    timing_test();

    // Test using augmented messages
    augmented_tests();

    // Try a CRC based on the (x + 1) polynominal, which is a factor in
    // many real-life polynominals and doesn't fit evenly in a byte.
    cout << "Doing one-bit polynominal CRC test." << endl;
    boost::crc_basic<1>  crc_1( 1 );
    crc_1.process_bytes( std_data, std_data_len );
    BOOST_TEST( crc_1.checksum() == 1 );

    // Test the function object interface
    cout << "Doing functional object interface test." << endl;
    boost::crc_optimal<16, 0x8005, 0, 0, true, true>  crc_16;
    crc_16 = std::for_each( std_data, std_data + std_data_len, crc_16 );
    BOOST_TEST( crc_16() == std_crc_16_result );

    return boost::exit_success;
}