mirror of
				https://github.com/saitohirga/WSJT-X.git
				synced 2025-10-31 04:50:34 -04:00 
			
		
		
		
	
		
			
	
	
		
			762 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			762 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
|  | //  Boost CRC test program file  ---------------------------------------------//
 | ||
|  | 
 | ||
|  | //  Copyright 2001, 2003, 2004 Daryle Walker.  Use, modification, and
 | ||
|  | //  distribution are subject to the Boost Software License, Version 1.0.  (See
 | ||
|  | //  accompanying file LICENSE_1_0.txt or a copy at
 | ||
|  | //  <http://www.boost.org/LICENSE_1_0.txt>.)
 | ||
|  | 
 | ||
|  | //  See <http://www.boost.org/libs/crc/> for the library's home page.
 | ||
|  | 
 | ||
|  | //  Revision History
 | ||
|  | //  28 Aug 2004  Added CRC tests for polynominals shorter than 8 bits
 | ||
|  | //               (Daryle Walker, by patch from Bert Klaps)
 | ||
|  | //  23 Aug 2003  Adjust to updated Test framework (Daryle Walker)
 | ||
|  | //  14 May 2001  Initial version (Daryle Walker)
 | ||
|  | 
 | ||
|  | 
 | ||
|  | #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/test/minimal.hpp>                // for main, etc.
 | ||
|  | #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
 | ||
|  | 
 | ||
|  | #if !(defined(BOOST_NO_DEPENDENT_TYPES_IN_TEMPLATE_VALUE_PARAMETERS) || (defined(BOOST_MSVC) && (BOOST_MSVC <= 1300)))
 | ||
|  | #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 ); | ||
|  | 
 | ||
|  | void  small_crc_test1(); | ||
|  | void  small_crc_test2(); | ||
|  | 
 | ||
|  | 
 | ||
|  | // 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_CHECK( fast_crc.checksum() == expected ); | ||
|  |     BOOST_CHECK( slow_crc.checksum() == expected ); | ||
|  |     BOOST_CHECK( 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_CHECK( 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_CHECK( 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_CHECK( fast_crc2.checksum() == slow_crc2.checksum() ); | ||
|  |     BOOST_CHECK( fast_crc2.checksum() == expected ); | ||
|  |     BOOST_CHECK( 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_FAIL( "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_CHECK( 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_CHECK( fast_tester.checksum() == slow_tester.checksum() ); | ||
|  |     BOOST_CHECK( fast_tester.checksum() == fast_checksum ); | ||
|  |     BOOST_CHECK( 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_CHECK( fast_tester.checksum() == slow_tester.checksum() ); | ||
|  |     BOOST_CHECK( fast_tester.checksum() != fast_checksum ); | ||
|  |     BOOST_CHECK( 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_CHECK( basic_result == optimal_result ); | ||
|  |     BOOST_CHECK( optimal_result == quick_result ); | ||
|  |     BOOST_CHECK( 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_CHECK( 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_CHECK( fast_tester.checksum() == slow_tester.checksum() ); | ||
|  |     ran_crc = big_to_native( ran_crc ); | ||
|  |     BOOST_CHECK( fast_tester.checksum() == ran_crc ); | ||
|  |     BOOST_CHECK( 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_CHECK( 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_CHECK( 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_CHECK( 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_CHECK( 0 != ran_crc_check ); | ||
|  | 
 | ||
|  |     #undef PRIVATE_ACRC_FUNC
 | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | // Run tests on CRCs below a byte in size (here, 3 bits)
 | ||
|  | void | ||
|  | small_crc_test1 | ||
|  | ( | ||
|  | ) | ||
|  | { | ||
|  |     std::cout << "Doing short-CRC (3-bit augmented) message tests." | ||
|  |      << std::endl; | ||
|  | 
 | ||
|  |     // The CRC standard is a SDH/SONET Low Order LCAS control word with CRC-3
 | ||
|  |     // taken from ITU-T G.707 (12/03) XIII.2.
 | ||
|  | 
 | ||
|  |     // Four samples, each four bytes; should all have a CRC of zero
 | ||
|  |     unsigned char const  samples[4][4] | ||
|  |       = { | ||
|  |             { 0x3A, 0xC4, 0x08, 0x06 }, | ||
|  |             { 0x42, 0xC5, 0x0A, 0x41 }, | ||
|  |             { 0x4A, 0xC5, 0x08, 0x22 }, | ||
|  |             { 0x52, 0xC4, 0x08, 0x05 } | ||
|  |         }; | ||
|  | 
 | ||
|  |     // Basic computer
 | ||
|  |     boost::crc_basic<3>  tester1( 0x03 ); | ||
|  | 
 | ||
|  |     tester1.process_bytes( samples[0], 4 ); | ||
|  |     BOOST_CHECK( tester1.checksum() == 0 ); | ||
|  | 
 | ||
|  |     tester1.reset(); | ||
|  |     tester1.process_bytes( samples[1], 4 ); | ||
|  |     BOOST_CHECK( tester1.checksum() == 0 ); | ||
|  | 
 | ||
|  |     tester1.reset(); | ||
|  |     tester1.process_bytes( samples[2], 4 ); | ||
|  |     BOOST_CHECK( tester1.checksum() == 0 ); | ||
|  | 
 | ||
|  |     tester1.reset(); | ||
|  |     tester1.process_bytes( samples[3], 4 ); | ||
|  |     BOOST_CHECK( tester1.checksum() == 0 ); | ||
|  | 
 | ||
|  |     // Optimal computer
 | ||
|  |     #define PRIVATE_CRC_FUNC   boost::crc<3, 0x03, 0, 0, false, false>
 | ||
|  |     #define PRIVATE_ACRC_FUNC  boost::augmented_crc<3, 0x03>
 | ||
|  | 
 | ||
|  |     BOOST_CHECK( 0 == PRIVATE_CRC_FUNC(samples[0], 4) ); | ||
|  |     BOOST_CHECK( 0 == PRIVATE_CRC_FUNC(samples[1], 4) ); | ||
|  |     BOOST_CHECK( 0 == PRIVATE_CRC_FUNC(samples[2], 4) ); | ||
|  |     BOOST_CHECK( 0 == PRIVATE_CRC_FUNC(samples[3], 4) ); | ||
|  | 
 | ||
|  |     // maybe the fix to CRC functions needs to be applied to augmented CRCs?
 | ||
|  | 
 | ||
|  |     #undef PRIVATE_ACRC_FUNC
 | ||
|  |     #undef PRIVATE_CRC_FUNC
 | ||
|  | } | ||
|  | 
 | ||
|  | // Run tests on CRCs below a byte in size (here, 7 bits)
 | ||
|  | void | ||
|  | small_crc_test2 | ||
|  | ( | ||
|  | ) | ||
|  | { | ||
|  |     std::cout << "Doing short-CRC (7-bit augmented) message tests." | ||
|  |      << std::endl; | ||
|  | 
 | ||
|  |     // The CRC standard is a SDH/SONET J0/J1/J2/N1/N2/TR TTI (trace message)
 | ||
|  |     // with CRC-7, o.a. ITU-T G.707 Annex B, G.832 Annex A.
 | ||
|  | 
 | ||
|  |     // Two samples, each sixteen bytes
 | ||
|  |     // Sample 1 is '\x80' + ASCII("123456789ABCDEF")
 | ||
|  |     // Sample 2 is '\x80' + ASCII("TTI UNAVAILABLE")
 | ||
|  |     unsigned char const  samples[2][16] | ||
|  |       = { | ||
|  |             { 0x80, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, | ||
|  |               0x42, 0x43, 0x44, 0x45, 0x46 }, | ||
|  |             { 0x80, 0x54, 0x54, 0x49, 0x20, 0x55, 0x4E, 0x41, 0x56, 0x41, 0x49, | ||
|  |               0x4C, 0x41, 0x42, 0x4C, 0x45 } | ||
|  |         }; | ||
|  |     unsigned const       results[2] = { 0x62, 0x23 }; | ||
|  | 
 | ||
|  |     // Basic computer
 | ||
|  |     boost::crc_basic<7>  tester1( 0x09 ); | ||
|  | 
 | ||
|  |     tester1.process_bytes( samples[0], 16 ); | ||
|  |     BOOST_CHECK( tester1.checksum() == results[0] ); | ||
|  | 
 | ||
|  |     tester1.reset(); | ||
|  |     tester1.process_bytes( samples[1], 16 ); | ||
|  |     BOOST_CHECK( tester1.checksum() == results[1] ); | ||
|  | 
 | ||
|  |     // Optimal computer
 | ||
|  |     #define PRIVATE_CRC_FUNC   boost::crc<7, 0x09, 0, 0, false, false>
 | ||
|  |     #define PRIVATE_ACRC_FUNC  boost::augmented_crc<7, 0x09>
 | ||
|  | 
 | ||
|  |     BOOST_CHECK( results[0] == PRIVATE_CRC_FUNC(samples[0], 16) ); | ||
|  |     BOOST_CHECK( results[1] == PRIVATE_CRC_FUNC(samples[1], 16) ); | ||
|  | 
 | ||
|  |     // maybe the fix to CRC functions needs to be applied to augmented CRCs?
 | ||
|  | 
 | ||
|  |     #undef PRIVATE_ACRC_FUNC
 | ||
|  |     #undef PRIVATE_CRC_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(); | ||
|  | 
 | ||
|  |     // Test with CRC types smaller than a byte
 | ||
|  |     small_crc_test1(); | ||
|  |     small_crc_test2(); | ||
|  | 
 | ||
|  |     // 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_CHECK( 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_CHECK( crc_16() == std_crc_16_result ); | ||
|  | 
 | ||
|  |     return boost::exit_success; | ||
|  | } |