$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
From: dwalker07_at_[hidden]
Date: 2008-08-21 04:05:55
Author: dlwalker
Date: 2008-08-21 04:05:53 EDT (Thu, 21 Aug 2008)
New Revision: 48279
URL: http://svn.boost.org/trac/boost/changeset/48279
Log:
Added md5_byte_context, a variant of md5_context that woks byte-wise instead of bit-wise, and hopefully optimized; changed defintion of compute_md5 to use md5_byte_context; updated grouping & promotion header
Text files modified: 
   sandbox/md5/boost/coding.hpp                       |    18 ++--                                    
   sandbox/md5/boost/coding/md5.hpp                   |    15 ++--                                    
   sandbox/md5/boost/coding/md5_context.hpp           |   138 ++++++++++++++++++++++++++++++++++++++- 
   sandbox/md5/boost/coding_fwd.hpp                   |     5                                         
   sandbox/md5/libs/coding/src/md5.cpp                |    37 ++++++++++                              
   sandbox/md5/libs/coding/test/md5_computer_test.cpp |    66 ++++++++++++++++++                      
   6 files changed, 253 insertions(+), 26 deletions(-)
Modified: sandbox/md5/boost/coding.hpp
==============================================================================
--- sandbox/md5/boost/coding.hpp	(original)
+++ sandbox/md5/boost/coding.hpp	2008-08-21 04:05:53 EDT (Thu, 21 Aug 2008)
@@ -1,17 +1,15 @@
 // Boost coding.hpp header file  ---------------------------------------------//
-
-// (C) Copyright Daryle Walker 2008.  Distributed under the Boost Software
-// License, Version 1.0.  (See the accompanying file LICENSE_1_0.txt or a copy
-// at <http://www.boost.org/LICENSE_1_0.txt>.)
-
-// See <http://www.boost.org/libs/coding> for documentation.
-
 /** \file
-    \brief  Group-inclusion of Boost.Coding components
+    \brief  Group-inclusion of Boost.Coding components.
 
     \#Includes all of the headers of Boost.Coding and promotes the public names
     to the main Boost namespace.
+ 
+    (C) Copyright Daryle Walker 2008.  Distributed under the Boost Software
+    License, Version 1.0. (See the accompanying file LICENSE_1_0.txt or a copy
+    at <http://www.boost.org/LICENSE_1_0.txt>.)
  */
+// See <http://www.boost.org/libs/coding> for documentation.
 
 #ifndef BOOST_CODING_HPP
 #define BOOST_CODING_HPP
@@ -27,8 +25,10 @@
 
 //  Namespace promotions  ----------------------------------------------------//
 
-// From <boost/coding/md5.hpp>
+// Ultimately from <boost/coding/md5.hpp>
 using coding::md5_digest;
+using coding::md5_context;
+using coding::md5_byte_context;
 using coding::md5_computer;
 using coding::compute_md5;
 
Modified: sandbox/md5/boost/coding/md5.hpp
==============================================================================
--- sandbox/md5/boost/coding/md5.hpp	(original)
+++ sandbox/md5/boost/coding/md5.hpp	2008-08-21 04:05:53 EDT (Thu, 21 Aug 2008)
@@ -19,7 +19,7 @@
 
 #include <boost/coding_fwd.hpp>
 #include <boost/coding/md5_digest.hpp>    // for boost::coding::md5_digest
-#include <boost/coding/md5_context.hpp>   // for b:c:md5_context (for grouping)
+#include <boost/coding/md5_context.hpp>   // for b:c:md5_(byte_)context
 #include <boost/coding/md5_computer.hpp>  // for boost::coding::md5_computer
 
 #include <cstddef>  // for std::size_t
@@ -48,15 +48,16 @@
     \return  The MD5 message digest of the data block.
 
     \see  boost::coding::md5_digest
-    \see  boost::coding::md5_computer
+    \see  boost::coding::md5_byte_context
  */
-inline md5_digest
-compute_md5( void const *buffer, std::size_t byte_count )
+inline md5_digest  compute_md5( void const *buffer, std::size_t byte_count )
 {
-    md5_computer  c;
+    md5_byte_context       c;
+    unsigned char const *  b = static_cast<unsigned char const *>( buffer );
 
-    c.process_bytes( buffer, byte_count );
-    return c.checksum();
+    while ( byte_count-- )
+        c( *b++ );
+    return c();
 }
 
 
Modified: sandbox/md5/boost/coding/md5_context.hpp
==============================================================================
--- sandbox/md5/boost/coding/md5_context.hpp	(original)
+++ sandbox/md5/boost/coding/md5_context.hpp	2008-08-21 04:05:53 EDT (Thu, 21 Aug 2008)
@@ -39,17 +39,31 @@
 #include <string>     // for std::string
 
 
+//  Control-macro definitions  -----------------------------------------------//
+
+// Control macro for whole-byte processing
+#ifndef BOOST_CODING_MD5_CONTROL_OPTIMIZE_BYTE_ENTRY
+/** \brief  Preprocessor control flag for optimized byte entry for MD5.
+
+    Indicates whether \c boost::coding::md5_byte_context should pass on bytes a
+    bit at a time or violate encapsulation by copying bytes whole into its inner
+    \c boost::coding::md5_context object.  Even if active, the optimization will
+    not happen unless the bits-per-byte count, \c CHAR_BIT, is a factor of the
+    MD5 packed-bit array size (512 bits).  If not overriden, it defaults to 1,
+    activating the optimization if possible.
+
+    \see  boost::coding::md5_byte_context
+ */
+#define BOOST_CODING_MD5_CONTROL_OPTIMIZE_BYTE_ENTRY  1
+#endif
+
+
 namespace boost
 {
 namespace coding
 {
 
 
-//  Forward declarations  ----------------------------------------------------//
-
-// None right now
-
-
 //  MD5 message-digest core computation class declaration  -------------------//
 
 /** \brief  A computer that produces MD5 message digests from consuming bits.
@@ -93,6 +107,7 @@
     product_type  operator ()() const;//@}
 
 private:
+    friend class md5_byte_context;
     friend class md5_computer;
 
     // Implementation types and meta-constants
@@ -323,6 +338,119 @@
 }
 
 
+//  MD5 message-digest byte-wise computation class declaration  --------------//
+
+/** \brief  A computer that produces MD5 message digests from consuming bytes.
+
+    This class is a variant of \c boost::coding::md5_context in that it consumes
+    values a byte at a time instead of bit-wise.  It uses the same algorithm,
+    but can optimize entry if \c CHAR_BIT is a factor of the block size (512
+    bits).  Besides computation, it also supports comparisons (equivalence only,
+    not ordering) and serialization.
+
+    \see  boost::coding::md5_digest
+    \see  boost::coding::md5_context
+    \see  BOOST_CODING_MD5_CONTROL_OPTIMIZE_BYTE_ENTRY
+ */
+class md5_byte_context
+{
+    typedef md5_byte_context  self_type;
+
+public:
+    // Types
+    /** \brief  Type of the produced output
+
+        Represents the result type, the checksums from hashing.
+     */
+    typedef md5_digest      product_type;
+    /** \brief  Type of the consumed input
+
+        Represents the argument type, the data to hash.
+     */
+    typedef unsigned char  consumed_type;
+
+    /*! \name Operators */ //@{
+    // Operators (use automatic copy-assignment)
+    //! Application, consumer
+    void          operator ()( consumed_type byte );
+    //! Equals
+    bool          operator ==( self_type const &o ) const;
+    //! Not-equals
+    bool          operator !=( self_type const &o ) const;
+    //! Application, producer
+    product_type  operator ()() const;//@}
+
+private:
+    // Member data
+    md5_context  inner;
+
+    /*! \name Persistence */ //@{
+    // Serialization
+    friend class boost::serialization::access;
+
+    //! Enables persistence with Boost.Serialization-compatible archives
+    template < class Archive >
+    void  serialize( Archive &ar, const unsigned int version );//@}
+
+};  // md5_byte_context
+
+
+//  MD5 message-digest byte-wise computation class member func. defintions  --//
+
+/** Compares computation contexts for equivalence.  Such contexts are equal if
+    their internal states are equal.  (This means that they should both return
+    the same checksum, and continue to do so as long as the same byte sequence
+    is submitted to both contexts.)
+
+    \param o  The right-side operand to be compared.
+
+    \retval true   \c *this and \p o are equivalent.
+    \retval false  \c *this and \p o are not equivalent.
+ */
+inline bool  md5_byte_context::operator ==( self_type const &o ) const
+{ return this->inner == o.inner; }
+
+/** Compares computation contexts for non-equivalence.  Such engines are unequal
+    if their internal states are unequal.  (Usually, the two contexts would
+    return checksums that differ either immediately or after the same byte
+    sequence is submitted to both contexts.  However, it is possible for two
+    contexts with differing input histories to have the same output checksum.
+    Worse, it is possible to deliberately create such a collision.)
+
+    \param o  The right-side operand to be compared.
+
+    \retval true   \c *this and \p o are not equivalent.
+    \retval false  \c *this and \p o are equivalent.
+ */
+inline bool  md5_byte_context::operator !=( self_type const &o ) const
+{ return !this->operator ==( o ); }
+
+/** Provides the computed check-sum of all the submitted bytes (as if the
+    message is complete), through a standard generator interface.
+
+    \return  The check-sum.
+ */
+inline md5_byte_context::product_type  md5_byte_context::operator ()() const
+{ return this->inner(); }
+
+/** Streams a byte-wise core computer to/from an archive using the
+    Boost.Serialization protocols.  This member function is meant to be called
+    only by the Boost.Serialization system, as needed.
+
+    \tparam  Archive  The type of \p ar.  It must conform to the requirements
+                      Boost.Serialization expects of archiving classes.
+
+    \param  ar       The archiving object that this object's representation will
+                     be streamed to/from.
+    \param  version  The version of the persistence format for this object.  (It
+                     should be zero, since this type just got created.)
+ */
+template < class Archive >
+inline void
+md5_byte_context::serialize( Archive &ar, const unsigned int version )
+{ ar & BOOST_SERIALIZATION_NVP( inner ); }
+
+
 }  // namespace coding
 }  // namespace boost
 
Modified: sandbox/md5/boost/coding_fwd.hpp
==============================================================================
--- sandbox/md5/boost/coding_fwd.hpp	(original)
+++ sandbox/md5/boost/coding_fwd.hpp	2008-08-21 04:05:53 EDT (Thu, 21 Aug 2008)
@@ -50,19 +50,20 @@
 
 //  From <boost/coding/md5_digest.hpp>  --------------------------------------//
 
-// Only has operator free-functions, #includes "md5_digest_core.hpp"
+// Has operator and support free-functions, #includes "md5_digest_core.hpp"
 
 
 //  From <boost/coding/md5_context.hpp>  -------------------------------------//
 
 class md5_context;
+class md5_byte_context;
 
 
 //  From <boost/coding/md5_computer.hpp>  ------------------------------------//
 
 class md5_computer;
 
-// Also has a support free-function
+// Has support free-functions
 
 
 //  From <boost/coding/md5.hpp>  ---------------------------------------------//
Modified: sandbox/md5/libs/coding/src/md5.cpp
==============================================================================
--- sandbox/md5/libs/coding/src/md5.cpp	(original)
+++ sandbox/md5/libs/coding/src/md5.cpp	2008-08-21 04:05:53 EDT (Thu, 21 Aug 2008)
@@ -26,6 +26,7 @@
 #include <boost/detail/endian.hpp>          // for BOOST_LITTLE_ENDIAN
 #include <boost/integer/integer_mask.hpp>   // for boost::integer_lo_mask
 #include <boost/math/common_factor_rt.hpp>  // for boost::math::gcd
+#include <boost/mpl/assert.hpp>             // for BOOST_MPL_ASSERT_RELATION
 #include <boost/typeof/typeof.hpp>          // for BOOST_AUTO
 
 #include <algorithm>  // for std::copy, fill
@@ -320,7 +321,8 @@
     // High-order-bit-first is also how the bit-oriented MD5 algorithm reads a
     // byte.  There is a bonus that an optimized byte-consumption routine can
     // copy a byte directly into the array for quick entry, at least if CHAR_BIT
-    // divides index.
+    // divides index.  See md5_byte_context::operator()(unsigned char) for the
+    // optimized byte-entry code.
 
     if ( bit )  byte |=  mask;
     else        byte &= ~mask;
@@ -570,6 +572,39 @@
 }
 
 
+//  MD5 message-digest byte-wise computation non-inline member definitions  --//
+
+/** Submits a byte for processing.
+
+    \param byte  The byte value to be submitted.
+
+    \post  Sorry, there is no externally-accessible state.  (However, the byte
+           is queued until enough have been collected to update the internal
+           hash.  If an update occurs, the queue is emptied.)
+ */
+void  md5_byte_context::operator ()( consumed_type byte )
+{
+#if (512 % CHAR_BIT == 0) && BOOST_CODING_MD5_CONTROL_OPTIMIZE_BYTE_ENTRY
+    // Copy the byte in whole.  It is already compatible with the format of the
+    // packed-bit array's packing.  Since the inner md5_context's entry checking
+    // is skipped, we have to redo the logic of md5_context::consume_bit here.
+    BOOST_MPL_ASSERT_RELATION( md5_context::bits_per_block::value, ==, 512 );
+    int const  index = this->inner.length % md5_context::bits_per_block::value;
+    int const  byte_index = index / CHAR_BIT;
+
+    BOOST_ASSERT( index % CHAR_BIT == 0 );
+    this->inner.queue[ byte_index ] = byte;
+    this->inner.length += CHAR_BIT;
+    if ( index + CHAR_BIT == md5_context::bits_per_block::value )
+        this->inner.update_hash();
+#else
+    // Enter each bit in the offical order (highest-order first)
+    for ( unsigned char  m = 1u << (CHAR_BIT - 1) ; m ; m >>= 1 )
+        this->inner( byte & m );
+#endif
+}
+
+
 //  MD5 message-digest computation non-inline member definitions  ------------//
 
 /** Sample of the table described in RFC 1321, section 3.4, paragraph 4.  Its
Modified: sandbox/md5/libs/coding/test/md5_computer_test.cpp
==============================================================================
--- sandbox/md5/libs/coding/test/md5_computer_test.cpp	(original)
+++ sandbox/md5/libs/coding/test/md5_computer_test.cpp	2008-08-21 04:05:53 EDT (Thu, 21 Aug 2008)
@@ -40,13 +40,12 @@
 #define PRIVATE_SHOW_MESSAGE( m )  BOOST_TEST_MESSAGE( m )
 #endif
 
-BOOST_TEST_DONT_PRINT_LOG_VALUE( boost::coding::md5_computer );
-
 
 #pragma mark Intro stuff
 
 // Put any using-ed types & templates, and typedefs here
 using boost::array;
+using boost::coding::md5_byte_context;
 using boost::coding::md5_computer;
 using boost::coding::md5_digest;
 
@@ -91,6 +90,8 @@
 
 
 // Mark any unprintable tested types here
+BOOST_TEST_DONT_PRINT_LOG_VALUE( boost::coding::md5_byte_context );
+BOOST_TEST_DONT_PRINT_LOG_VALUE( boost::coding::md5_computer );
 
 
 #pragma mark -
@@ -691,13 +692,74 @@
     BOOST_CHECK_NE( test, c2 );
 }
 
+// Byte-optimized MD5-context object tests
+BOOST_AUTO_TEST_CASE( md5_byte_context_test )
+{
+    using boost::coding::md5_byte_context;
+    using boost::coding::md5_context;
+
+    // Default construction and production
+    md5_byte_context const  c1;
+    md5_computer            scratch;
+
+    BOOST_CHECK_EQUAL( c1(), scratch.context()() );
+
+    // Equality
+    md5_byte_context  c2;
+
+    BOOST_CHECK( c1 == c2 );
+    BOOST_CHECK( !(c2 != c1) );
+
+    // Consumption
+    unsigned char const  test_value = 0x02u;
+
+    c2( test_value );
+    scratch.process_byte( test_value );
+    BOOST_CHECK_EQUAL( c2(), scratch.context()() );
+
+    // Inequality
+    BOOST_CHECK( c1 != c2 );
+    BOOST_CHECK( !(c2 == c1) );
+
+    // Copy construction
+    md5_byte_context  test( c2 );
+
+    BOOST_CHECK_EQUAL( test, c2 );
+    BOOST_REQUIRE_NE( test, c1 );
+
+    // More consumption, but make sure the hash queue turns over
+    int const  test_length = 512 / CHAR_BIT + !!(512 % CHAR_BIT);
+
+    for ( int  i = test_length ; i ; --i )
+        c2( test_value );
+    scratch.process_byte_copies( test_value, test_length );
+    BOOST_CHECK_EQUAL( c2(), scratch.checksum() );
+
+    // Quick S11N check
+    std::stringstream  ss;
+
+    write_xml_archive( ss, c1, "test" );
+    PRIVATE_SHOW_MESSAGE( ss.str() );
+    read_xml_archive( ss, test, "test" );
+    BOOST_CHECK_EQUAL( test, c1 );
+    BOOST_CHECK_NE( test, c2 );
+}
+
 // Single-call function test
 BOOST_AUTO_TEST_CASE( compute_md5_test )
 {
     using boost::coding::compute_md5;
 
+    // Empty check
     BOOST_CHECK_EQUAL( compute_md5(0, 0), md5_empty_data );
 
+    // Check against another component
+    unsigned char const  test_value = 0x6Fu;
+    md5_computer         scratch;
+
+    scratch.process_byte( test_value );
+    BOOST_CHECK_EQUAL( compute_md5(&test_value, 1u), scratch.checksum() );
+
     // How do we get consistent data when we can't count on CHAR_BIT being the
     // same everywhere?  Do we just screw over testers without 8-bit bytes or
     // ones without ASCII (or superset)?  If so, then we could use the other