Boost logo

Boost-Commit :

From: dwalker07_at_[hidden]
Date: 2008-07-03 14:56:31


Author: dlwalker
Date: 2008-07-03 14:56:30 EDT (Thu, 03 Jul 2008)
New Revision: 47053
URL: http://svn.boost.org/trac/boost/changeset/47053

Log:
Refactored code common to any binary coder to a new header; made variable names within 'update_hash' clearer; touched up comment for 'generate_hashing_table'.
Added:
   sandbox/md5/boost/coding/operations.hpp (contents, props changed)
Text files modified:
   sandbox/md5/boost/coding/md5.hpp | 626 +++------------------------------------
   sandbox/md5/boost/coding_fwd.hpp | 15
   sandbox/md5/libs/coding/src/md5.cpp | 64 ++--
   3 files changed, 104 insertions(+), 601 deletions(-)

Modified: sandbox/md5/boost/coding/md5.hpp
==============================================================================
--- sandbox/md5/boost/coding/md5.hpp (original)
+++ sandbox/md5/boost/coding/md5.hpp 2008-07-03 14:56:30 EDT (Thu, 03 Jul 2008)
@@ -21,22 +21,19 @@
 
 #include <boost/array.hpp> // for boost::array
 #include <boost/assert.hpp> // for BOOST_ASSERT
-#include <boost/cstdint.hpp> // for boost::uint_least8_t
-#include <boost/foreach.hpp> // for BOOST_FOREACH
+#include <boost/coding/operations.hpp> // for b:c:queued_bit_processing_base
 #include <boost/integer.hpp> // for boost::uint_t
 #include <boost/serialization/access.hpp> // for boost::serialization::access
 #include <boost/static_assert.hpp> // for BOOST_STATIC_ASSERT
 #include <boost/typeof/typeof.hpp> // for BOOST_AUTO
 
-#include <algorithm> // for std::equal, swap, copy
+#include <algorithm> // for std::equal, swap
 #include <climits> // for CHAR_BIT
-#include <cstddef> // for std::size_t, NULL
-#include <cstring> // for std::strlen
-#include <ios> // for std::ios
+#include <cstddef> // for std::size_t
+#include <ios> // for std::ios_base
 #include <istream> // for std::basic_istream
 #include <locale> // for std::use_facet, ctype
 #include <ostream> // for std::basic_ostream
-#include <utility> // for std::make_pair
 
 
 namespace boost
@@ -108,109 +105,43 @@
 
     \see boost::coding::md5_digest
     \see boost::coding::compute_md5(void const*,std::size_t)
+
+ \todo Replace "uint_fast64_t" with "uint_t<significant_bits_per_length>::
+ fast", where "significant_bits_per_length" is 64. (Need to tweak
+ Boost.Integer to support 64-bit types.) Also need to make a
+ convienent constant for the "16" in the base class declaration.
+ (It's the number of words per block, from RFC 1321, section 3.4.)
+ \todo The implementation base class was originally inherited privately, but
+ the core member functions would give access errors when needed. The
+ solution, for now, was either make \e all the base classes (direct
+ and indirect) friends of this class, or change the inheritance to
+ either public or protected. I haven't figured out why yet, or how to
+ switch back to private inheritance without needing to add friendship.
+ (Furthermore, I couldn't use \c base_type to establish friendship;
+ i.e., both "friend base_type" and "friend class base_type" didn't
+ work. I don't know why either.)
  */
 class md5_computer
+ : protected queued_bit_processing_base<md5_computer, uint_fast64_t, 16u *
+ md5_digest::bits_per_word>
 {
- /** \brief A class for submitting bit-oriented data for a MD5 message
- digest in a function-object interface.
+ typedef queued_bit_processing_base<md5_computer, uint_fast64_t, 16u *
+ md5_digest::bits_per_word> base_type;
 
- This class represents objects that are proxy views to their owning MD5
- computing object. The proxy interface appears as a function object that
- takes a \c bool value, which passes it on to the owning computer for
- processing. It should be suitable STL-like algorithms that use such a
- function object. It supports assignment to work with \c std::for_each
- and other algorithms that can return a post-use function object.
-
- \see boost::coding::md5_computer
- \see #byte_applicator
- \see #bits
-
- \todo The current store-by-reference semantics for the owning computer
- means that said owner is always changed during an application of
- \c *this. Maybe write-back to the owner should only be explicit
- with the assignment operator.
- */
- class bit_applicator
- {
- friend class md5_computer;
- md5_computer *parent_;
- explicit bit_applicator( md5_computer &p ) : parent_( &p ) {};
- public:
- //! Application
- void operator ()( bool v );
- //! Copy-assignment
- bit_applicator & operator =( bit_applicator const &c );
-
- }; // bit_applicator
-
- /** \brief A class for submitting byte-oriented data for a MD5 message
- digest in a function-object interface.
-
- This class represents objects that are proxy views to their owning MD5
- computing object. The proxy interface appears as a function object that
- takes an <code>unsigned char</code> value, which passes it on to the
- owning computer for processing. It should be suitable STL-like
- algorithms that use such a function object. It supports assignment to
- work with \c std::for_each and other algorithms that can return a
- post-use function object.
-
- \see boost::coding::md5_computer
- \see #bit_applicator
- \see #bytes
-
- \todo The current store-by-reference semantics for the owning computer
- means that said owner is always changed during an application of
- \c *this. Maybe write-back to the owner should only be explicit
- with the assignment operator.
- */
- class byte_applicator
- {
- friend class md5_computer;
- md5_computer *parent_;
- explicit byte_applicator( md5_computer &p ) : parent_( &p ) {};
- public:
- //! Application
- void operator ()( unsigned char v );
- //! Copy-assignment
- byte_applicator & operator =( byte_applicator const &c );
+ friend void base_type::process_bit( bool ); // needs "update_hash" access
 
- }; // byte_applicator
+ // Implementation constants, followed by sanity checks
+ static std::size_t const words_per_block = base_type::queue_length /
+ md5_digest::bits_per_word;
 
- // Implementation constants
- static std::size_t const words_per_block = 16u; // RFC 1321, section 3.4
+ BOOST_STATIC_ASSERT( (base_type::queue_length % md5_digest::bits_per_word)
+ == 0u );
+ BOOST_STATIC_ASSERT( words_per_block == 16u ); // RFC 1321, section 3.4
 
 public:
     // Special application interface
- /** \brief Proxy for bit-oriented application interface
-
- Accesses an interface where <code>*this</code> can be used as a function
- object take can take a single \c bool value as input. It cannot be
- reseated from <code>*this</code>, but assignment to it will copy the
- other's owner's state to <code>*this</code>, enabling algorithms that
- return updated function objects to work.
-
- \attention Since #bit_applicator stores a non-constant reference to its
- owner, the owner will be change through any application
- through \c bits, even if \c bits is passed by value.
-
- \see #bit_applicator
- */
- bit_applicator bits;
- /** \brief Proxy for byte-oriented application interface
-
- Accesses an interface where <code>*this</code> can be used as a function
- object take can take a single <code>unsigned char</code> value as input.
- It cannot be reseated from <code>*this</code>, but assignment to it will
- copy the other's owner's state to <code>*this</code>, enabling
- algorithms that return updated function objects to work.
-
- \attention Since #byte_applicator stores a non-constant reference to
- its owner, the owner will be change through any application
- through \c bytes, even if \c bytes is passed by value.
-
- \see #byte_applicator
- */
- byte_applicator bytes;
+ using base_type::bits;
+ using base_type::bytes;
 
     // Constants
     /** \brief Number of bits for length quantities
@@ -229,8 +160,7 @@
         (The input processing member functions trigger a hash right after a bit
         fills the queue.)
      */
- static std::size_t const bits_per_block = words_per_block *
- md5_digest::bits_per_word;
+ static std::size_t const bits_per_block = base_type::queue_length;
 
     /** \brief Hashing sine table
 
@@ -254,7 +184,7 @@
         Represents the type used for sizing parameters and returns. It should
         be an unsigned integer.
      */
- typedef std::size_t size_type;
+ typedef base_type::size_type size_type;
 
     /** \brief Type of MD message lengths
 
@@ -291,36 +221,23 @@
     // Inspectors
     //! Returns the count of bits read so far
     length_type bits_read() const;
- //! Returns the count of bits not hashed into the buffer yet
- length_type bits_unbuffered() const;
     //! Returns the checksum buffer of hashed bits
     buffer_type last_buffer() const;
 
- //! Copies out the unhashed bits
- template < typename OutputIterator >
- OutputIterator copy_unbuffered( OutputIterator o ) const;//@}
+ using base_type::bits_unbuffered;
+ using base_type::copy_unbuffered;
 
     /*! \name Bit-stream reading */ //@{
     // Input processing
- //! Enters one bit for hashing
- void process_bit( bool bit );
- //! Enters part of a byte for hashing
- void process_bits( unsigned char bits, size_type bit_count );
- //! Enters several bits, all of the same value, for hashing
- void process_bit_copies( bool value, size_type bit_count );
-
- //! Enters a whole byte for hashing
- void process_byte( unsigned char byte );
- //! Enters several bytes, all of the same value, for hashing
- void process_byte_copies( unsigned char value, size_type byte_count );
-
- //! Enters a range of bytes in memory for hashing
- void process_block( void const *bytes_begin, void const *bytes_end );
- //! Enters a byte buffer in memory for hashing
- void process_bytes( void const *buffer, size_type byte_count );
+ using base_type::process_bit;
+ using base_type::process_bits;
+ using base_type::process_bit_copies;
+ using base_type::process_byte;
+ using base_type::process_byte_copies;
+ using base_type::process_block;
+ using base_type::process_bytes;
+ using base_type::process_octet;
 
- //! Enters an octet for hashing
- void process_octet( uint_least8_t octet );
     //! Enters a word for hashing
     void process_word( md5_digest::word_type word );
     //! Enters a double-word for hashing
@@ -358,7 +275,7 @@
 
         \return The computed hashing sine table
 
- \relates #hashing_table
+ \see #hashing_table
      */
     static array<md5_digest::word_type, 64> generate_hashing_table();
 
@@ -379,22 +296,16 @@
        // may have to do save/load split; support XML archives
 
     // Implementation functions
- void update_hash();
+ void update_hash( bool const *queue_b, bool const *queue_e );
 
     // Implementation types
     typedef md5_computer self_type;
 
- typedef uint_fast64_t ilength_type;
- // replace w/ uint_t<significant_bits_per_length>::fast
     typedef uint_t<md5_digest::bits_per_word>::fast iword_type;
     typedef array<iword_type, md5_digest::words_per_digest> ibuffer_type;
 
- typedef array<bool, bits_per_block> block_type;
-
     // (Computation) member data
- ilength_type length_;
     ibuffer_type buffer_;
- block_type unbuffered_;
 
     static ibuffer_type const initial_buffer_;
 
@@ -621,73 +532,6 @@
 }
 
 
-// MD5 computation special applicator operator definitions -----------------//
-
-/** Calls <code><var>o</var>.process_bit( <var>v</var> )</code>, where
- \p o is the owning \c md5_computer of <code>*this</code>.
-
- \param v The bit to process.
-
- \see boost::coding::md5_computer::process_bit(bool)
- */
-inline
-void
-md5_computer::bit_applicator::operator ()( bool v )
-{
- this->parent_->process_bit( v );
-}
-
-/** Calls <code>this-&gt;<var>p</var> = <var>c.p</var></code>, where
- \p p holds the owning \c md5_computer of a particular proxy.
-
- \return <code>*this</code>
-
- \see boost::coding::md5_computer::operator=(md5_computer const&)
- */
-inline
-md5_computer::bit_applicator &
-md5_computer::bit_applicator::operator =
-(
- md5_computer::bit_applicator const & c
-)
-{
- *this->parent_ = *c.parent_;
- return *this;
-}
-
-/** Calls <code><var>o</var>.process_byte( <var>v</var> )</code>, where
- \p o is the owning \c md5_computer of <code>*this</code>.
-
- \param v The byte to process.
-
- \see boost::coding::md5_computer::process_byte(unsigned char)
- */
-inline
-void
-md5_computer::byte_applicator::operator ()( unsigned char v )
-{
- this->parent_->process_byte( v );
-}
-
-/** Calls <code>this-&gt;<var>p</var> = <var>c.p</var></code>, where
- \p p holds the owning \c md5_computer of a particular proxy.
-
- \return <code>*this</code>
-
- \see boost::coding::md5_computer::operator=(md5_computer const&)
- */
-inline
-md5_computer::byte_applicator &
-md5_computer::byte_applicator::operator =
-(
- md5_computer::byte_applicator const & c
-)
-{
- *this->parent_ = *c.parent_;
- return *this;
-}
-
-
 // MD5 message-digest computation constructor definitions ------------------//
 
 /** Constructs a \c md5_computer set to initial conditions. That is, with the
@@ -702,8 +546,8 @@
  */
 inline
 md5_computer::md5_computer()
- : bits( *this ), bytes( *this )
- , length_(), buffer_( self_type::initial_buffer_ ), unbuffered_()
+ : base_type()
+ , buffer_( self_type::initial_buffer_ )
 {
     BOOST_ASSERT( this->test_invariant() );
 }
@@ -724,8 +568,8 @@
  */
 inline
 md5_computer::md5_computer( md5_computer const &c )
- : bits( *this ), bytes( *this )
- , length_( c.length_ ), buffer_( c.buffer_ ), unbuffered_( c.unbuffered_ )
+ : base_type( c )
+ , buffer_( c.buffer_ )
 {
     BOOST_ASSERT( this->test_invariant() );
 }
@@ -743,24 +587,9 @@
 md5_computer::length_type
 md5_computer::bits_read() const
 {
- return this->length_;
-}
-
-/** Returns the number of bits that have not been hashed. Hashing occurs only
- after every \c #bits_per_block bit entries, so this member function can
- confirm queued stragglers. (The identities of hashed bits are not
- retrievable.)
-
- \return How many bits are queued to be hashed.
-
- \see #bits_read()
- \see #bits_per_block
- */
-inline
-md5_computer::length_type
-md5_computer::bits_unbuffered() const
-{
- return this->length_ % self_type::bits_per_block;
+ // Don't count any wrap-around past 2**64
+ // (Use mask value once Boost.Integer is upped to 64-bit support)
+ return this->base_type::bits_read() & 0xFFFFFFFFFFFFFFFFull;
 }
 
 /** Returns the checksum of all the bits that have been hashed so far. Hashing
@@ -781,35 +610,6 @@
     return r;
 }
 
-/** Copies the last submitted bits that have not yet hashed into the running
- checksum, starting from the oldest submission. Use \c #bits_unbuffered()
- for advance notice of how many iterations are done. (Always less than
- \c #bits_per_block elements are copied.)
-
- \pre At least \c #bits_unbuffered() more elements are free to be created
- and/or assigned through \p o
-
- \tparam OutputIterator The type of the iterator submitted. It should match
- the requirements of either an output or a forward
- (or above) mutable iterator over something that can
- receive \c bool values via dereferenced assignment.
-
- \param o The iterator starting the destination range.
-
- \return \p o after copying.
-
- \see #bits_unbuffered()
- \see #bits_per_block
- */
-template < typename OutputIterator >
-inline
-OutputIterator
-md5_computer::copy_unbuffered( OutputIterator o ) const
-{
- return std::copy( this->unbuffered_.begin(), this->unbuffered_.begin() +
- this->bits_unbuffered(), o );
-}
-
 
 // MD5 message-digest computation assignment member function definitions ---//
 
@@ -826,10 +626,7 @@
 void
 md5_computer::reset()
 {
- // The "bits" and "bytes" members don't/can't reset. The "unbuffered_"
- // member doesn't need it either since "length_" reset will cause existing
- // elements of "unbuffered_" to be ignored.
- this->length_ = 0u;
+ this->base_type::reset();
     this->buffer_ = self_type::initial_buffer_;
 
     BOOST_ASSERT( this->test_invariant() );
@@ -856,12 +653,8 @@
 void
 md5_computer::assign( md5_computer const &c )
 {
- // Don't/can't reseat the function object proxies; only the elements of
- // "unbuffered_" that will remain significant need to be copied.
- this->length_ = c.length_;
+ this->base_type::assign( c );
     this->buffer_ = c.buffer_;
- std::copy( c.unbuffered_.begin(), c.unbuffered_.begin() +
- c.bits_unbuffered(), this->unbuffered_.begin() );
 
     BOOST_ASSERT( this->test_invariant() );
 }
@@ -882,9 +675,8 @@
     using std::swap;
 
     // Swap the computation members (don't reseat the function object proxies)
- swap( this->length_, other.length_ );
+ this->base_type::swap( other );
     swap( this->buffer_, other.buffer_ );
- swap( this->unbuffered_, other.unbuffered_ );
 
     BOOST_ASSERT( this->test_invariant() );
     BOOST_ASSERT( other.test_invariant() );
@@ -893,308 +685,6 @@
 
 // MD5 message-digest computation bit-input member function definitions ----//
 
-/** Submits a single bit for computation. The bit is queued; if this bit fills
- the queue, the queue's bits are hashed and the queue is emptied.
-
- \param bit The bit value to be submitted.
-
- \post <code>#bits_read() == <var>old_this</var>.bits_read() + 1</code>
- \post <code>#bits_unbuffered() == bits_read() % #bits_per_block ? 0 :
- <var>old_this</var>.bits_unbuffered() + 1</code>
- \post <code>#last_buffer() == bits_read() % bits_per_block ?
- <var>new_value</var> : <var>old_this</var>.last_buffer()</code> (The
- new value is computed with the algorithm described in RFC 1321,
- section 3.4.)
- \post If <code>bits_read() % bits_per_block == 0</code>, then
- <code>#copy_unbuffered(<var>o1</var>)</code> leaves \p o1 unused,
- otherwise <code>copy_unbuffered(<var>o2</var>) -
- <var>old_this</var>.copy_unbuffered(<var>o2</var>) == 1</code>
- (assuming that \p o2 is, at least, a forward iterator)
- */
-inline
-void
-md5_computer::process_bit( bool bit )
-{
- this->unbuffered_[ this->bits_unbuffered() ] = bit;
- if ( 0u == (++this->length_ % self_type::bits_per_block) )
- this->update_hash();
- BOOST_ASSERT( this->test_invariant() );
-}
-
-/** Submits part of a byte for computation. Bits are submitted starting from
- the highest-order bit to the lowest.
-
- \pre <code>0 &lt; <var>bit_count</var> &lt;= CHAR_BIT</code>
-
- \param bits The byte from which the values are submitted.
- \param bit_count The number of bits to submit, starting from the
- 2<sup><var>bit_count</var> - 1</sup> place down to the
- ones-place.
-
- \post <code>#bits_read() == <var>old_this</var>.bits_read() +
- <var>bit_count</var></code>
- \post <code>#bits_unbuffered() == (<var>old_this</var>.bits_unbuffered() +
- <var>bit_count</var>) % bits_per_block</code>
- \post <code>#last_buffer() == <var>old_this</var>.bits_unbuffered() +
- <var>bit_count</var> &gt;= bits_per_block ? <var>new_value</var> :
- <var>old_this</var>.last_buffer()</code> (The new value is computed
- with the algorithm described in RFC 1321, section 3.4.)
- \post If <code>bits_read() % bits_per_block == 0</code>, then
- <code>#copy_unbuffered(<var>o1</var>)</code> leaves \p o1 unused,
- otherwise if <code><var>old_this</var>.bits_unbuffered() +
- <var>bit_count</var> &lt; bits_per_block,</code> then
- <code>copy_unbuffered(<var>o2</var>) -
- <var>old_this</var>.copy_unbuffered(<var>o2</var>) ==
- <var>bit_count</var></code> (assuming that \p o2 is, at least, a
- forward iterator), otherwise the range \p o3 to
- <code>copy_unbuffered(<var>o3</var>)</code> contains the
- <code><var>old_this</var>.bits_unbuffered() + <var>bit_count</var> -
- bits_per_block</code> lowest-order bits of \p bits
-
- \see #process_bit(bool)
- */
-inline
-void
-md5_computer::process_bits
-(
- unsigned char bits,
- md5_computer::size_type bit_count
-)
-{
- BOOST_ASSERT( (0u < bit_count) && (bit_count <= CHAR_BIT) );
- for ( unsigned char m = 0x01u << (bit_count - 1u) ; bit_count-- ; m >>= 1 )
- this->process_bit( bits & m );
-}
-
-/** Submits multiple copies of a single bit value for computation.
-
- \param value The bit value to be submitted.
- \param bit_count The number of bits to submit.
-
- \post <code>#bits_read() == <var>old_this</var>.bits_read() +
- <var>bit_count</var></code>
- \post <code>#bits_unbuffered() == (<var>old_this</var>.bits_unbuffered() +
- <var>bit_count</var>) % bits_per_block</code>
- \post <code>#last_buffer() == (<var>old_this</var>.bits_unbuffered() +
- <var>bit_count</var> &gt;= bits_per_block) ? <var>new_value</var> :
- <var>old_this</var>.last_buffer()</code> (The new value is computed
- with the algorithm described in RFC 1321, section 3.4.)
- \post If <code>bits_read() % bits_per_block == 0</code>, then
- <code>#copy_unbuffered(<var>o1</var>)</code> leaves \p o1 unused,
- otherwise if <code><var>old_this</var>.bits_unbuffered() +
- <var>bit_count</var> &lt; bits_per_block,</code> then
- <code>copy_unbuffered(<var>o2</var>) -
- <var>old_this</var>.copy_unbuffered(<var>o2</var>) ==
- <var>bit_count</var></code> (assuming that \p o2 is, at least, a
- forward iterator), otherwise the range \p o3 to
- <code>copy_unbuffered(<var>o3</var>)</code> contains
- <code>(<var>old_this</var>.bits_unbuffered() + <var>bit_count</var>)
- % bits_per_block</code> copies of \p value
-
- \see #process_bit(bool)
- */
-inline
-void
-md5_computer::process_bit_copies
-(
- bool value,
- md5_computer::size_type bit_count
-)
-{
- while ( bit_count-- )
- this->process_bit( value );
-}
-
-/** Submits a byte for computation. The bits are submitted starting from the
- highest-order bit to the lowest.
-
- \param byte The byte value to be submitted.
-
- \post <code>#bits_read() == <var>old_this</var>.bits_read() +
- CHAR_BIT</code>
- \post <code>#bits_unbuffered() == (<var>old_this</var>.bits_unbuffered() +
- CHAR_BIT) % bits_per_block</code>
- \post <code>#last_buffer() == (<var>old_this</var>.bits_unbuffered() +
- CHAR_BIT &gt;= bits_per_block) ? <var>new_value</var> :
- <var>old_this</var>.last_buffer()</code> (The new value is computed
- with the algorithm described in RFC 1321, section 3.4.)
- \post If <code>bits_read() % bits_per_block == 0</code>, then
- <code>#copy_unbuffered(<var>o1</var>)</code> leaves \p o1 unused,
- otherwise if <code><var>old_this</var>.bits_unbuffered() + CHAR_BIT
- &lt; bits_per_block,</code> then <code>copy_unbuffered(<var>o2</var>)
- - <var>old_this</var>.copy_unbuffered(<var>o2</var>) ==
- CHAR_BIT</code> (assuming that \p o2 is, at least, a forward
- iterator), otherwise the range \p o3 to
- <code>copy_unbuffered(<var>o3</var>)</code> contains the
- <code><var>old_this</var>.bits_unbuffered() + CHAR_BIT -
- bits_per_block</code> lowest-order bits of \p byte
-
- \see #process_bits(unsigned char,#size_type)
- */
-inline
-void
-md5_computer::process_byte( unsigned char byte )
-{
- this->process_bits( byte, CHAR_BIT );
-}
-
-/** Submits multiple copies of a single byte value for computation.
-
- \param value The byte value to be submitted.
- \param byte_count The number of bytes to submit.
-
- \post <code>#bits_read() == <var>old_this</var>.bits_read() +
- <var>byte_count</var> * CHAR_BIT</code>
- \post <code>#bits_unbuffered() == (<var>old_this</var>.bits_unbuffered() +
- <var>byte_count</var> * CHAR_BIT) % bits_per_block</code>
- \post <code>#last_buffer() == (<var>old_this</var>.bits_unbuffered() +
- <var>byte_count</var> * CHAR_BIT &gt;= bits_per_block) ?
- <var>new_value</var> : <var>old_this</var>.last_buffer()</code> (The
- new value is computed with the algorithm described in RFC 1321,
- section 3.4.)
- \post If <code>bits_read() % bits_per_block == 0</code>, then
- <code>#copy_unbuffered(<var>o1</var>)</code> leaves \p o1 unused,
- otherwise if <code><var>old_this</var>.bits_unbuffered() +
- <var>byte_count</var> * CHAR_BIT &lt; bits_per_block,</code> then
- <code>copy_unbuffered(<var>o2</var>) -
- <var>old_this</var>.copy_unbuffered(<var>o2</var>) ==
- <var>bit_count</var> * CHAR_BIT</code> (assuming that \p o2 is, at
- least, a forward iterator), otherwise the range \p o3 to
- <code>copy_unbuffered(<var>o3</var>)</code> contains
- <code>(<var>old_this</var>.bits_unbuffered() + <var>byte_count</var>
- * CHAR_BIT) % bits_per_block</code> bits from copies of \p value
-
- \see #process_byte(unsigned char)
- */
-inline
-void
-md5_computer::process_byte_copies
-(
- unsigned char value,
- md5_computer::size_type byte_count
-)
-{
- while ( byte_count-- )
- this->process_byte( value );
-}
-
-/** Submits bytes, delimited by a pointer range, for computation.
-
- \pre If \p bytes_begin is not \c NULL, then \p bytes_end has to be
- reachable from \p bytes_begin via forward iterations of their
- equivalent <code>unsigned char const *</code> values, otherwise
- \p bytes_end has to be \c NULL too
-
- \param bytes_begin The start of the byte range to be submitted.
- \param bytes_end One-past-the-end of the byte range in \p bytes_begin.
-
- \post <code>#bits_read() == <var>old_this</var>.bits_read() +
- <var>L</var> * CHAR_BIT</code>, where \p L is number of bytes in the
- range from \p bytes_begin to just before \p bytes_end
- \post <code>#bits_unbuffered() == (<var>old_this</var>.bits_unbuffered() +
- <var>L</var> * CHAR_BIT) % bits_per_block</code>
- \post <code>#last_buffer() == (<var>old_this</var>.bits_unbuffered() +
- <var>L</var> * CHAR_BIT &gt;= bits_per_block) ? <var>new_value</var>
- : <var>old_this</var>.last_buffer()</code> (The new value is
- computed with the algorithm described in RFC 1321, section 3.4.)
- \post If <code>bits_read() % bits_per_block == 0</code>, then
- <code>#copy_unbuffered(<var>o1</var>)</code> leaves \p o1 unused,
- otherwise if <code><var>old_this</var>.bits_unbuffered() +
- <var>L</var> * CHAR_BIT &lt; bits_per_block,</code> then
- <code>copy_unbuffered(<var>o2</var>) -
- <var>old_this</var>.copy_unbuffered(<var>o2</var>) ==
- <var>L</var> * CHAR_BIT</code> (assuming that \p o2 is, at least, a
- forward iterator), otherwise the range \p o3 to
- <code>copy_unbuffered(<var>o3</var>)</code> contains
- <code>(<var>old_this</var>.bits_unbuffered() + <var>L</var> *
- CHAR_BIT) % bits_per_block</code> trailing bits from the byte range
-
- \see #process_byte(unsigned char)
- */
-inline
-void
-md5_computer::process_block( void const *bytes_begin, void const *bytes_end )
-{
- BOOST_ASSERT( (bytes_begin == NULL) == (bytes_end == NULL) );
- BOOST_FOREACH( unsigned char b, std::make_pair(static_cast<unsigned char
- const *>( bytes_begin ), static_cast<unsigned char const *>( bytes_end )) )
- this->process_byte( b );
-}
-
-/** Submits bytes, bounded by a pointer and length, for computation.
-
- \pre If \p buffer is \c NULL, then \p byte_count must be zero
-
- \param buffer The start of the byte range to be submitted.
- \param byte_count Number of (leading) bytes to use from the range.
-
- \post <code>#bits_read() == <var>old_this</var>.bits_read() +
- <var>byte_count</var> * CHAR_BIT</code>
- \post <code>#bits_unbuffered() == (<var>old_this</var>.bits_unbuffered() +
- <var>byte_count</var> * CHAR_BIT) % bits_per_block</code>
- \post <code>#last_buffer() == (<var>old_this</var>.bits_unbuffered() +
- <var>byte_count</var> * CHAR_BIT &gt;= bits_per_block) ?
- <var>new_value</var> : <var>old_this</var>.last_buffer()</code> (The
- new value is computed with the algorithm described in RFC 1321,
- section 3.4.)
- \post If <code>bits_read() % bits_per_block == 0</code>, then
- <code>#copy_unbuffered(<var>o1</var>)</code> leaves \p o1 unused,
- otherwise if <code><var>old_this</var>.bits_unbuffered() +
- <var>byte_count</var> * CHAR_BIT &lt; bits_per_block,</code> then
- <code>copy_unbuffered(<var>o2</var>) -
- <var>old_this</var>.copy_unbuffered(<var>o2</var>) ==
- <var>byte_count</var> * CHAR_BIT</code> (assuming that \p o2 is, at
- least, a forward iterator), otherwise the range \p o3 to
- <code>copy_unbuffered(<var>o3</var>)</code> contains
- <code>(<var>old_this</var>.bits_unbuffered() + <var>byte_count</var>
- * CHAR_BIT) % bits_per_block</code> trailing bits from the buffer
-
- \see #process_block(void const*,void const*)
- */
-inline
-void
-md5_computer::process_bytes
-(
- void const * buffer,
- md5_computer::size_type byte_count
-)
-{
- BOOST_ASSERT( buffer || !byte_count );
- this->process_block( buffer, static_cast<unsigned char const *>(buffer) +
- byte_count );
-}
-
-/** Submits an octet for computation. The bits are submitted starting from the
- highest-order bit to the lowest.
-
- \param octet The octet value to be submitted.
-
- \post <code>#bits_read() == <var>old_this</var>.bits_read() + 8</code>
- \post <code>#bits_unbuffered() == (<var>old_this</var>.bits_unbuffered() +
- 8) % bits_per_block</code>
- \post <code>#last_buffer() == (<var>old_this</var>.bits_unbuffered() + 8
- &gt;= bits_per_block) ? <var>new_value</var> :
- <var>old_this</var>.last_buffer()</code> (The new value is computed
- with the algorithm described in RFC 1321, section 3.4.)
- \post If <code>bits_read() % bits_per_block == 0</code>, then
- <code>#copy_unbuffered(<var>o1</var>)</code> leaves \p o1 unused,
- otherwise if <code><var>old_this</var>.bits_unbuffered() + 8 &lt;
- bits_per_block,</code> then <code>copy_unbuffered(<var>o2</var>) -
- <var>old_this</var>.copy_unbuffered(<var>o2</var>) == 8</code>
- (assuming that \p o2 is, at least, a forward iterator), otherwise the
- range \p o3 to <code>copy_unbuffered(<var>o3</var>)</code> contains
- the <code><var>old_this</var>.bits_unbuffered() + 8 -
- bits_per_block</code> lowest-order bits of \p octet
-
- \see #process_bits(unsigned char,#size_type)
- */
-inline
-void
-md5_computer::process_octet( uint_least8_t octet )
-{
- this->process_bits( octet, 8u );
-}
-
 /** Submits 32-bit MD-word for computation. The word is submitted an octet at a
     time, from the lowest-order octet to the highest.
 
@@ -1311,9 +801,7 @@
     // Don't compare the function object proxies since they don't carry
     // significant state. (Furthermore, they can't change once initalized and
     // don't have any comparison operators.)
- return ( this->length_ == c.length_ ) && ( this->buffer_ == c.buffer_ ) &&
- std::equal( this->unbuffered_.begin(), this->unbuffered_.begin() +
- this->bits_unbuffered(), c.unbuffered_.begin() );
+ return ( this->buffer_ == c.buffer_ ) && this->base_type::operator ==( c );
 }
 
 /** Compares MD5 message computers for non-equivalence. Such computers are

Added: sandbox/md5/boost/coding/operations.hpp
==============================================================================
--- (empty file)
+++ sandbox/md5/boost/coding/operations.hpp 2008-07-03 14:56:30 EDT (Thu, 03 Jul 2008)
@@ -0,0 +1,897 @@
+// Boost coding/operations.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 Definitions of coding helper base class templates
+
+ Contains the definition of templates that can be used for base classes of
+ bit- and byte-encoding computer types.
+ */
+
+#ifndef BOOST_CODING_OPERATIONS_HPP
+#define BOOST_CODING_OPERATIONS_HPP
+
+#include <boost/coding_fwd.hpp>
+
+#include <boost/array.hpp> // for boost::array
+#include <boost/assert.hpp> // for BOOST_ASSERT
+#include <boost/concept/assert.hpp> // for BOOST_CONCEPT_ASSERT
+#include <boost/concept_check.hpp> // for boost::OutputIterator
+#include <boost/cstdint.hpp> // for boost::uint_least8_t
+#include <boost/static_assert.hpp> // for BOOST_STATIC_ASSERT
+#include <boost/type_traits.hpp> // for boost::is_class, is_integral, etc.
+
+#include <algorithm> // for std::copy, swap, equal
+#include <climits> // for CHAR_BIT
+
+
+namespace boost
+{
+namespace coding
+{
+
+
+// Byte-processing base class template declaration -------------------------//
+
+/** \brief Base class template for byte-processing operations
+
+ This template is intended to base a class using the curiously recurring
+ template pattern to gain completed definitions of common byte-processing
+ operations.
+
+ \pre \p Derived is a class or class template and it must have, either
+ directly or through an intermediate base class, an unambiguous
+ non-static member function named \c process_byte that returns \c void
+ and takes one argument of type <code>unsigned char</code>. (A
+ different, yet compatible, signature is acceptable.)
+ \pre \p SizeType is a built-in unsigned integral type.
+
+ \tparam Derived The final operand type that this class template will form
+ a base. Any intermediate helper class templates should
+ pass \p Derived on to \c byte_processing_base.
+ \tparam SizeType The type used for size parameters. If not given,
+ \c std::size_t is the default.
+
+ \todo Using #bytes always changes \c *this. Is there some way to hold off
+ updates until explicit assignment?
+ */
+template < class Derived, typename SizeType >
+class byte_processing_base
+{
+ // Parameter checks (can't check for the existence of "process_byte")
+ BOOST_STATIC_ASSERT( is_class<Derived>::value );
+ BOOST_STATIC_ASSERT( is_integral<SizeType>::value &&
+ is_unsigned<SizeType>::value );
+
+ // Byte-wise application proxy class
+ class byte_applicator
+ {
+ friend class byte_processing_base;
+ Derived & source_;
+ explicit byte_applicator( Derived &source )
+ : source_( source ) {}
+ public:
+ void operator ()( unsigned char byte )
+ { this->source_.process_byte(byte); }
+ byte_applicator & operator =( byte_applicator const &c )
+ { this->source_ = c.source_; return *this; }
+ }; // byte_applicator
+
+public:
+ // Special application interface
+ /** \brief Proxy for byte-oriented application interface
+
+ Accesses an interface where <code>*this</code> can be used as a function
+ object take can take a single <code>unsigned char</code> value as input.
+ It cannot be reseated from <code>*this</code>, but assignment to it will
+ copy the other's owner's state to <code>*this</code>, enabling
+ algorithms that return updated function objects to work.
+
+ \attention Since #byte_applicator stores a non-constant reference to
+ its owner, the owner will be change through any application
+ through \c bytes, even if \c bytes is passed by value.
+ */
+ byte_applicator bytes;
+
+ /*! \name Byte-stream reading */ //@{
+ // Types
+ /** \brief Type of size values
+
+ Represents the type used for sizing parameters.
+ */
+ typedef SizeType size_type;
+
+ // Input processing
+ //! Enters several bytes, all of the same value
+ void process_byte_copies( unsigned char value, size_type byte_count );
+
+ //! Enters a range of bytes in memory
+ void process_block( void const *bytes_begin, void const *bytes_end );
+ //! Enters a byte buffer in memory
+ void process_bytes( void const *buffer, size_type byte_count );//@}
+
+ /*! \name Operators */ //@{
+ // Operators
+ //! Copy-assignment
+ byte_processing_base & operator =( byte_processing_base const & );//@}
+
+protected:
+ // Implementation types
+ /** \brief Final operand type
+
+ Represents the type that should ultimately inherit from this template.
+ */
+ typedef Derived derived_type;
+
+ // Lifetime management (use automatic destructor)
+ //! Default construction
+ byte_processing_base();
+ //! Copy construction
+ byte_processing_base( byte_processing_base const & );
+
+}; // byte_processing_base
+
+
+// Bit-processing base class template declarations -------------------------//
+
+/** \brief Base class template for bit-processing operations, big endian
+
+ This template is intended to base a class using the curiously recurring
+ template pattern to gain completed definitions of common bit-processing
+ operations. Bits within a byte are processed in order starting from the
+ most-significant places.
+
+ \pre \p Derived is a class or class template and it must have, either
+ directly or through an intermediate base class, an unambiguous
+ non-static member function named \c process_bit that returns \c void
+ and takes a single \c bool argument. (A different, yet compatible,
+ signature is acceptable.)
+ \pre \p SizeType is a built-in unsigned integral type.
+
+ \tparam Derived The final operand type that this class template will form
+ a base. Any intermediate helper class templates should
+ pass \p Derived on to \c bit_processing_base.
+ \tparam SizeType The type used for size parameters. If not given,
+ \c std::size_t is the default.
+
+ \see boost::coding::byte_processing_base
+
+ \todo Using #bits always changes \c *this. Is there some way to hold off
+ updates until explicit assignment?
+ */
+template < class Derived, typename SizeType >
+class bit_processing_b_base
+ : public byte_processing_base<Derived, SizeType>
+{
+ typedef byte_processing_base<Derived, SizeType> base_type;
+
+ // The parameter checks that the base class uses are acceptable. (Except
+ // that we can't check for the existence of "process_bit".)
+
+ // Bit-wise application proxy class
+ class bit_applicator
+ {
+ friend class bit_processing_b_base;
+ Derived & source_;
+ explicit bit_applicator( Derived &source )
+ : source_( source ) {}
+ public:
+ void operator ()( bool bit )
+ { this->source_.process_bit(bit); }
+ bit_applicator & operator =( bit_applicator const &c )
+ { this->source_ = c.source_; return *this; }
+ }; // bit_applicator
+
+public:
+ // Special application interface
+ /** \brief Proxy for bit-oriented application interface
+
+ Accesses an interface where <code>*this</code> can be used as a function
+ object take can take a single \c bool value as input. It cannot be
+ reseated from <code>*this</code>, but assignment to it will copy the
+ other's owner's state to <code>*this</code>, enabling algorithms that
+ return updated function objects to work.
+
+ \attention Since #bit_applicator stores a non-constant reference to its
+ owner, the owner will be change through any application
+ through \c bits, even if \c bits is passed by value.
+
+ \see #bit_applicator
+ */
+ bit_applicator bits;
+
+ /*! \name Bit-stream reading */ //@{
+ // Types
+ /** \brief Type of size values
+
+ Represents the type used for sizing parameters.
+ */
+ typedef typename base_type::size_type size_type;
+
+ // Input processing
+ //! Enters lowest-signficant part of a byte, relatively high-order bit first
+ void process_bits( unsigned char bits, size_type bit_count );
+ //! Enters several bits, all of the same value
+ void process_bit_copies( bool value, size_type bit_count );
+
+ //! Enters a whole byte, high-order bit first
+ void process_byte( unsigned char byte );
+
+ //! Enters an octet, highest bit first
+ void process_octet( uint_least8_t octet );//@}
+
+ /*! \name Operators */ //@{
+ // Operators
+ //! Copy-assignment
+ bit_processing_b_base & operator =( bit_processing_b_base const &c );//@}
+
+protected:
+ // Implementation types
+ /** \brief Final operand type
+
+ Represents the type that should ultimately inherit from this template.
+ */
+ typedef typename base_type::derived_type derived_type;
+
+ // Lifetime management (use automatic destructor)
+ //! Default construction
+ bit_processing_b_base();
+ //! Copy construction
+ bit_processing_b_base( bit_processing_b_base const &c );
+
+}; // bit_processing_b_base
+
+
+// Queued bit-processing base class template declarations ------------------//
+
+/** \brief Base class template for queued bit-processing operations
+
+ This template is intended to base a class using the curiously recurring
+ template pattern to gain a definition of a bit-queueing operation, plus some
+ inspectors on the bit queue. Bits, either individually or within a byte,
+ are processed in submission order, but in fixed-size runs. Bits are kept in
+ a queue until enough bits have been saved, then a full bit pack is processed
+ in one shot.
+
+ \pre \p Derived is a class or class template and it must have, either
+ directly or through an intermediate base class, an unambiguous
+ non-static member function named \c update_hash that returns nothing
+ (i.e. \c void) but takes two <code>bool const *</code> bounding an
+ array segment. (A different, yet compatible, signature is
+ acceptable.)
+ \pre \p LengthType is a built-in unsigned integral type.
+ \pre <code><var>QueueLength</var> &gt;= 2</code>. (If \p QueueLength is
+ less than two, then \c update_hash will be called after \e every
+ submission, which would make having a queue pointless.)
+ \pre \p SizeType is a built-in unsigned integral type.
+
+ \tparam Derived The final operand type that this class template will
+ form a base. Any intermediate helper class templates
+ should pass \p Derived on to
+ \c queued_bit_processing_b_base.
+ \tparam LengthType The type used for queue-size parameters.
+ \tparam QueueLength The number of processed bits to queue between hashings.
+ \tparam SizeType The type used for processing-size parameters. If not
+ given, \c std::size_t is the default.
+
+ \see boost::coding::bit_processing_b_base
+ */
+template < class Derived, typename LengthType, LengthType QueueLength, typename
+ SizeType >
+class queued_bit_processing_base
+ : public bit_processing_b_base<Derived, SizeType>
+{
+ typedef bit_processing_b_base<Derived, SizeType> base_type;
+
+ // Parameter checks (some template arguments are checked by the base class
+ // template; can't check for the existence of "update_hash".)
+ BOOST_STATIC_ASSERT( is_integral<LengthType>::value &&
+ is_unsigned<LengthType>::value );
+ BOOST_STATIC_ASSERT( QueueLength >= 2u );
+
+public:
+ /*! \name Inspection */ //@{
+ // Types
+ /** \brief Type of length values
+
+ Represents the type used for processing- and queueing-size results.
+ */
+ typedef LengthType length_type;
+
+ // Constants
+ //! Number of bits in the hash queue
+ static length_type const queue_length = QueueLength;
+
+ // Inspectors
+ //! Returns the count of bits read so far, hashed and queued
+ length_type bits_read() const;
+ //! Returns the count of the queued bits
+ length_type bits_unbuffered() const;
+
+ //! Copies out the queued bits
+ template < typename OutputIterator >
+ OutputIterator copy_unbuffered( OutputIterator o ) const;//@}
+
+ /*! \name Bit-stream reading */ //@{
+ // More types
+ /** \brief Type of size values
+
+ Represents the type used for reading-size parameters.
+ */
+ typedef typename base_type::size_type size_type;
+
+ // Input processing
+ //! Enters one bit for hashing
+ void process_bit( bool bit );//@}
+
+ /*! \name Operators */ //@{
+ // Operators (use automatic copy-assignment operator)
+ //! Equals
+ bool operator ==( queued_bit_processing_base const &c ) const;
+ //! Not-equals
+ bool operator !=( queued_bit_processing_base const &c ) const;//@}
+
+protected:
+ // Implementation types
+ /** \brief Final operand type
+
+ Represents the type that should ultimately inherit from this template.
+ */
+ typedef typename base_type::derived_type derived_type;
+
+ // Lifetime management (use automatic copy constructor and destructor)
+ //! Default construction
+ queued_bit_processing_base();
+
+ /*! \name Assignment */ //@{
+ // Assignment
+ //! Sets state back to initial conditions
+ void reset();
+ //! Changes the current state to a copy of another object's
+ void assign( queued_bit_processing_base const &c );
+
+ //! Exchanges state with another object
+ void swap( queued_bit_processing_base &other );//@}
+
+private:
+ // More implementation types
+ typedef array<bool, queue_length> queue_type;
+
+ // Member data
+ length_type bit_count;
+ queue_type queued_bits;
+
+}; // queued_bit_processing_base
+
+
+// Byte-processing base class template member definitions ------------------//
+
+/** Constructs a byte processor set to initial conditions.
+
+ \post \c #bytes points to \c *this
+ */
+template < class Derived, typename SizeType >
+inline
+byte_processing_base<Derived, SizeType>::byte_processing_base()
+ : bytes( *static_cast<derived_type *>(this) )
+{
+}
+
+/** Constructs a byte processor to the same significant state as another.
+
+ \post \c #bytes points to \c *this
+ */
+template < class Derived, typename SizeType >
+inline
+byte_processing_base<Derived, SizeType>::byte_processing_base
+(
+ byte_processing_base const & // unused
+)
+ : bytes( *static_cast<derived_type *>(this) )
+{
+}
+
+/** Submits multiple copies of a single byte value for processing.
+
+ \param value The byte value to be submitted.
+ \param byte_count The number of bytes to submit.
+
+ \post This object's \c process_byte member function has been called
+ \p byte_count times with \p value as the parameter.
+ */
+template < class Derived, typename SizeType >
+inline
+void
+byte_processing_base<Derived, SizeType>::process_byte_copies
+(
+ unsigned char value,
+ size_type byte_count
+)
+{
+ while ( byte_count-- )
+ this->bytes( value );
+}
+
+/** Submits bytes, delimited by a pointer range, for processing.
+
+ \pre If \p bytes_begin is not \c NULL, then \p bytes_end has to be
+ reachable from \p bytes_begin via forward iterations of their
+ equivalent <code>unsigned char const *</code> values, otherwise
+ \p bytes_end has to be \c NULL too.
+
+ \param bytes_begin The start of the byte range to be submitted.
+ \param bytes_end One-past-the-end of the byte range in \p bytes_begin.
+
+ \post This object's \c process_byte member function has been called for
+ each byte in the given range, starting from the one at the address
+ \p bytes_begin to the byte just before the \p bytes_end mark.
+ */
+template < class Derived, typename SizeType >
+inline
+void
+byte_processing_base<Derived, SizeType>::process_block
+(
+ void const * bytes_begin,
+ void const * bytes_end
+)
+{
+ // Parameter check (can't check if bytes_end is reachable from bytes_begin)
+ BOOST_ASSERT( !bytes_begin == !bytes_end );
+
+ for ( unsigned char const * p =
+ static_cast<unsigned char const *>(bytes_begin) ; p != bytes_end ; ++p )
+ this->bytes( *p );
+}
+
+/** Submits bytes, bounded by a pointer and length, for processing.
+
+ \pre If \p buffer is \c NULL, then \p byte_count must be zero.
+
+ \param buffer The start of the byte range to be submitted.
+ \param byte_count Number of (leading) bytes to use from the range.
+
+ \post This object's \c process_byte member function has been called for
+ each byte in the given range, starting from the one at the address
+ \p buffer, going forward for \p byte_count bytes total.
+ */
+template < class Derived, typename SizeType >
+inline
+void
+byte_processing_base<Derived, SizeType>::process_bytes
+(
+ void const * buffer,
+ size_type byte_count
+)
+{
+ // Parameter check
+ BOOST_ASSERT( buffer || !byte_count );
+
+ for ( unsigned char const * p = static_cast<unsigned char const *>(buffer)
+ ; byte_count-- ; ++p )
+ this->bytes( *p );
+}
+
+/** Changes a byte processor to have the same observable state as a given
+ processor. (The function object proxy isn't reseated, however.)
+
+ \return \c *this
+
+ \post \c #bytes \e still points to \c *this
+ */
+template < class Derived, typename SizeType >
+inline
+byte_processing_base<Derived, SizeType> &
+byte_processing_base<Derived, SizeType>::operator =
+(
+ byte_processing_base const & // unused
+)
+{
+ // Do nothing, so "bytes" can't be reseated
+ return *this;
+}
+
+
+// Bit-processing base class template member definitions -------------------//
+
+/** Constructs a bit processor set to initial conditions.
+
+ \post \c #bits points to \c *this
+ */
+template < class Derived, typename SizeType >
+inline
+bit_processing_b_base<Derived, SizeType>::bit_processing_b_base()
+ : base_type()
+ , bits( *static_cast<derived_type *>(this) )
+{
+}
+
+/** Constructs a bit processor to the same computation state as \p c.
+
+ \param c The original object to be copied.
+
+ \post \c #bits points to \c *this
+ */
+template < class Derived, typename SizeType >
+inline
+bit_processing_b_base<Derived, SizeType>::bit_processing_b_base
+(
+ bit_processing_b_base const & c
+)
+ : base_type( c )
+ , bits( *static_cast<derived_type *>(this) )
+{
+}
+
+/** Submits part of a byte for processing. The lowest-order bits are submitted
+ starting from the relatively highest-order bit to the lowest.
+
+ \pre <code>0 &lt;= <var>bit_count</var> &lt;= CHAR_BIT</code>.
+
+ \param bits The byte from which the values are submitted.
+ \param bit_count The number of bits to submit.
+
+ \post This object's \c process_bit member function has been called for
+ each qualifying bit within \p bits, starting from the bit at the
+ 2<sup><var>bit_count</var> - 1</sup>-place, going down to the
+ ones-place. (If \p bit_count is zero, no calls are made.)
+ */
+template < class Derived, typename SizeType >
+inline
+void
+bit_processing_b_base<Derived, SizeType>::process_bits
+(
+ unsigned char bits,
+ size_type bit_count
+)
+{
+ // Parameter check
+ BOOST_ASSERT( (0u <= bit_count) && (bit_count <= CHAR_BIT) );
+
+ while ( bit_count-- )
+ this->bits( bits & (0x01u << bit_count) );
+}
+
+/** Submits multiple copies of a single bit value for processing.
+
+ \param value The bit value to be submitted.
+ \param bit_count The number of bits to submit.
+
+ \post This object's \c process_bit member function has been called
+ \p bit_count times with \p value as the parameter.
+ */
+template < class Derived, typename SizeType >
+inline
+void
+bit_processing_b_base<Derived, SizeType>::process_bit_copies
+(
+ bool value,
+ size_type bit_count
+)
+{
+ while ( bit_count-- )
+ this->bits( value );
+}
+
+/** Submits a byte for processing. The bits are submitted starting from the
+ highest-order bit to the lowest. Note that this member function enables the
+ inherited input-processing member functions \c #process_byte_copies,
+ \c #process_block, and \c #process_bytes.
+
+ \param byte The byte value to be submitted.
+
+ \post This object's \c process_bit member function has been called for
+ each bit in the given \p byte, starting from the high-order bit,
+ going down to the low-order bit.
+
+ \see #process_bits(unsigned char,#size_type)
+ */
+template < class Derived, typename SizeType >
+inline
+void
+bit_processing_b_base<Derived, SizeType>::process_byte( unsigned char byte )
+{
+ this->process_bits( byte, CHAR_BIT );
+}
+
+/** Submits an octet for processing. The bits are submitted starting from the
+ highest-order bit to the lowest. Note that a byte may be larger than eight
+ bits, so the lowest-significant bits within the containing byte (or larger
+ register) are chosen. This way, you don't have to shift up your octet value
+ by <code>sizeof(<var>octet</var>) * CHAR_BIT - 8</code> (or whatever) bits.
+
+ \param octet The octet value to be submitted.
+
+ \post This object's \c process_bit member function has been called for
+ each qualifying bit in \p octet, starting from the bit at the
+ 128s-place, going down to the ones-place.
+
+ \see #process_bits(unsigned char,#size_type)
+ */
+template < class Derived, typename SizeType >
+inline
+void
+bit_processing_b_base<Derived, SizeType>::process_octet( uint_least8_t octet )
+{
+ // CHAR_BIT >= 8 (C-1999, section 5.2.4.2.1) -> all octet values can safely
+ // be converted to "unsigned char," no matter what "uint_least8_t" is.
+ this->process_bits( octet, 8u );
+}
+
+/** Changes a bit processor to have the same observable state as a given
+ processor. (No function object proxies are reseated, however.)
+
+ \param c The source object with the new state.
+
+ \return \c *this
+
+ \post \c #bits \e still points to \c *this
+ */
+template < class Derived, typename SizeType >
+inline
+bit_processing_b_base<Derived, SizeType> &
+bit_processing_b_base<Derived, SizeType>::operator =
+(
+ bit_processing_b_base const & c
+)
+{
+ // Do nothing, so "bits" can't be reseated
+ this->base_type::operator =( c );
+ return *this;
+}
+
+
+// Queued bit-processing base class template member definitions ------------//
+
+/** Represents the number of submitted bits that are queued until that queue
+ is emptied as a single block to be hashed. The count of unhashed bits
+ is always less than this value. (The input processing member functions,
+ like \c #process_bit, trigger \c update_hash right after a bit fills the
+ queue.)
+ */
+template < class Derived, typename LengthType, LengthType QueueLength, typename
+ SizeType >
+typename queued_bit_processing_base<Derived, LengthType, QueueLength,
+ SizeType>::length_type const queued_bit_processing_base<Derived, LengthType,
+ QueueLength, SizeType>::queue_length;
+
+/** Constructs an empty processing queue.
+
+ \post <code>#bits_read() == 0</code>.
+ \post <code>#copy_unbuffered(<var>o</var>)</code> leaves \p o unused.
+ */
+template < class Derived, typename LengthType, LengthType QueueLength, typename
+ SizeType >
+inline
+queued_bit_processing_base<Derived, LengthType, QueueLength,
+ SizeType>::queued_bit_processing_base()
+ : bit_count(), queued_bits()
+{
+}
+
+/** Returns the number of bits that have been processed, both those that have
+ been hashed and those that are on queue. (Beware if the number of
+ submissions has exceeded <code>std::numeric_limits&lt; #length_type
+ &gt;::max()</code>.)
+
+ \return How many bits have been submitted, hashed and queued.
+ */
+template < class Derived, typename LengthType, LengthType QueueLength, typename
+ SizeType >
+inline
+typename queued_bit_processing_base<Derived, LengthType, QueueLength,
+ SizeType>::length_type
+queued_bit_processing_base<Derived, LengthType, QueueLength,
+ SizeType>::bits_read() const
+{
+ return this->bit_count;
+}
+
+/** Returns the number of bits that are still in the queue, unhashed. Hashing
+ occurs only after every \c #queue_length bit submissions, so this member
+ function can confirm queued stragglers. (The identities of hashed bits are
+ not retrievable.)
+
+ \return How many bits are queued to be hashed.
+
+ \see #bits_read()
+ \see #queue_length
+ */
+template < class Derived, typename LengthType, LengthType QueueLength, typename
+ SizeType >
+inline
+typename queued_bit_processing_base<Derived, LengthType, QueueLength,
+ SizeType>::length_type
+queued_bit_processing_base<Derived, LengthType, QueueLength,
+ SizeType>::bits_unbuffered() const
+{
+ return this->bit_count % queue_length;
+}
+
+/** Copies the last submitted bits that have not yet hashed starting from the
+ oldest submission. Use \c #bits_unbuffered() for advance notice of how
+ many iterations are done. (Always less than \c #queue_length elements are
+ copied.)
+
+ \pre At least \c #bits_unbuffered() more elements are free to be created
+ and/or assigned through \p o.
+
+ \tparam OutputIterator The type of the iterator submitted. It should match
+ the requirements of either an output or a forward
+ (or above) mutable iterator over something that can
+ receive \c bool values via dereferenced assignment.
+
+ \param o The iterator starting the destination range.
+
+ \return \p o after copying.
+
+ \see #bits_unbuffered()
+ \see #queue_length
+ */
+template < class Derived, typename LengthType, LengthType QueueLength, typename
+ SizeType >
+template < typename OutputIterator >
+inline
+OutputIterator
+queued_bit_processing_base<Derived, LengthType, QueueLength,
+ SizeType>::copy_unbuffered( OutputIterator o ) const
+{
+ // Parameter check
+ BOOST_CONCEPT_ASSERT( (boost::OutputIterator<OutputIterator, bool>) );
+
+ return std::copy( this->queued_bits.begin(), this->queued_bits.begin() +
+ this->bits_unbuffered(), o );
+}
+
+/** Changes an object to be like it was default-constructed.
+
+ \post <code>#bits_read() == 0</code>.
+ \post <code>#copy_unbuffered(<var>o</var>)</code> leaves \p o unused.
+
+ \see #queued_bit_processing_base()
+ */
+template < class Derived, typename LengthType, LengthType QueueLength, typename
+ SizeType >
+inline
+void
+queued_bit_processing_base<Derived, LengthType, QueueLength, SizeType>::reset()
+{
+ // With this setting, any used bits in "queued_bits" will be ignored.
+ this->bit_count = 0u;
+}
+
+/** Changes an object to be like the given object.
+
+ \param c The object with the new state to be copied.
+
+ \post <code>*this == <var>c</var></code>.
+ */
+template < class Derived, typename LengthType, LengthType QueueLength, typename
+ SizeType >
+inline
+void
+queued_bit_processing_base<Derived, LengthType, QueueLength, SizeType>::assign(
+ queued_bit_processing_base const &c )
+{
+ // Just rip off the automatically-defined copy-assignment operator
+ *this = c;
+}
+
+/** Swaps the content of this object with another.
+
+ \param other The other object to trade state with this object.
+
+ \post <code>*this == <var>old_other</var> &amp;&amp; <var>old_this</var> ==
+ <var>other</var></code>.
+ */
+template < class Derived, typename LengthType, LengthType QueueLength, typename
+ SizeType >
+inline
+void
+queued_bit_processing_base<Derived, LengthType, QueueLength, SizeType>::swap(
+ queued_bit_processing_base &other )
+{
+ // Use the appropriate swap via Koeing look-up
+ using std::swap;
+
+ // Swap members
+ swap( this->bit_count, other.bit_count );
+ swap( this->queued_bits, other.queued_bits );
+}
+
+/** Submits a single bit to the processing queue. If this bit fills the queue,
+ the queue's bits are hashed and the queue is emptied.
+
+ \param bit The bit value to be submitted.
+
+ \post <code>#bits_read() == <var>old_this</var>.bits_read() + 1</code>.
+ \post <code>#bits_unbuffered() == bits_read() % #queue_length ? 0 :
+ <var>old_this</var>.bits_unbuffered() + 1</code>.
+ \post This object's \c update_hash member function has been called,
+ accepting all the bits from the queue in submission order.
+ \post If <code>bits_read() % queue_length == 0</code>, then
+ <code>#copy_unbuffered(<var>o1</var>)</code> leaves \p o1 unused,
+ otherwise <code>std::distance(
+ <var>old_this</var>.copy_unbuffered(<var>o2</var>),
+ copy_unbuffered(<var>o2</var>) ) == 1</code> (assuming that \p o2 is,
+ at least, a forward iterator).
+ */
+template < class Derived, typename LengthType, LengthType QueueLength, typename
+ SizeType >
+inline
+void
+queued_bit_processing_base<Derived, LengthType, QueueLength,
+ SizeType>::process_bit( bool bit )
+{
+ this->queued_bits[ this->bits_unbuffered() ] = bit;
+
+ if ( (++this->bit_count % queue_length) == 0u )
+ {
+ static_cast<derived_type *>(this)->update_hash(
+ this->queued_bits.begin(), this->queued_bits.end() );
+ }
+}
+
+/** Compares bit processing queues for equivalence. Such processing queues are
+ equal if all of the corresponding parts of their significant state (data
+ length and bit queue) are equal. In other words, if \c *this and \p c are
+ equivalent, then:
+ - <code>#bits_read() == <var>c</var>.bits_read()</code>.
+ - Given two empty containers \p x1 and \p x2 of the same standard-acting
+ type that holds \c bool elements and has the \c push_back member function,
+ after applying <code>#copy_unbuffered( std::back_inserter(<var>x1</var>)
+ )</code> and <code><var>c</var>.copy_unbuffered(
+ std::back_inserter(<var>x2</var>) )</code>, <code><var>x1</var> ==
+ <var>x2</var></code>.
+
+ \param c The right-side operand to be compared.
+
+ \retval true \c *this and \p c are equivalent.
+ \retval false \c *this and \p c are not equivalent.
+
+ \see #bits_read()
+ \see #copy_unbuffered(OutputIterator)
+ */
+template < class Derived, typename LengthType, LengthType QueueLength, typename
+ SizeType >
+inline
+bool
+queued_bit_processing_base<Derived, LengthType, QueueLength, SizeType>::operator
+ ==( queued_bit_processing_base const &c ) const
+{
+ return ( this->bit_count == c.bit_count ) && std::equal(
+ this->queued_bits.begin(), this->queued_bits.begin() +
+ this->bits_unbuffered(), c.queued_bits.begin() );
+}
+
+/** Compares bit processing queues for non-equivalence. Such processing queues
+ are unequal if at least one set of corresponding parts of their significant
+ state (data length or bit queue) are unequal.
+
+ \param c The right-side operand to be compared.
+
+ \retval true \c *this and \p c are not equivalent.
+ \retval false \c *this and \p c are equivalent.
+
+ \see #operator==(queued_bit_processing_base const&)const
+ */
+template < class Derived, typename LengthType, LengthType QueueLength, typename
+ SizeType >
+inline
+bool
+queued_bit_processing_base<Derived, LengthType, QueueLength, SizeType>::operator
+ !=( queued_bit_processing_base const &c ) const
+{
+ return !this->operator ==( c );
+}
+
+
+} // namespace coding
+} // namespace boost
+
+
+#endif // BOOST_CODING_OPERATIONS_HPP

Modified: sandbox/md5/boost/coding_fwd.hpp
==============================================================================
--- sandbox/md5/boost/coding_fwd.hpp (original)
+++ sandbox/md5/boost/coding_fwd.hpp 2008-07-03 14:56:30 EDT (Thu, 03 Jul 2008)
@@ -16,6 +16,8 @@
 #ifndef BOOST_CODING_FWD_HPP
 #define BOOST_CODING_FWD_HPP
 
+#include <cstddef> // for std::size_t
+
 
 namespace boost
 {
@@ -29,6 +31,19 @@
 {
 
 
+// From <boost/coding/operations.hpp> --------------------------------------//
+
+template < class Derived, typename SizeType = std::size_t >
+class byte_processing_base;
+
+template < class Derived, typename SizeType = std::size_t >
+class bit_processing_b_base;
+
+template < class Derived, typename LengthType, LengthType QueueLength, typename
+ SizeType = std::size_t >
+class queued_bit_processing_base;
+
+
 // From <boost/coding/md5.hpp> ---------------------------------------------//
 
 class md5_digest;

Modified: sandbox/md5/libs/coding/src/md5.cpp
==============================================================================
--- sandbox/md5/libs/coding/src/md5.cpp (original)
+++ sandbox/md5/libs/coding/src/md5.cpp 2008-07-03 14:56:30 EDT (Thu, 03 Jul 2008)
@@ -319,80 +319,80 @@
 
 // Hash an entire block into the running checksum, using RFC 1321, section 3.4
 void
-md5_computer::update_hash()
+md5_computer::update_hash( bool const *queue_b, bool const *queue_e )
 {
     using std::size_t;
 
     // Convert the queued bit block to a word block
- std::valarray<self_type::iword_type> x( self_type::words_per_block ),
- xx( x ); // setup for later
+ std::valarray<iword_type> words( words_per_block ), scratch( queue_e -
+ queue_b );
 
- for ( size_t i = 0u ; i < self_type::words_per_block ; ++i )
+ BOOST_ASSERT( scratch.size() == bits_per_block );
+ std::copy( queue_b, queue_e, &scratch[0] );
+ for ( size_t i = 0u ; i < words_per_block ; ++i )
     {
         // Use the default inner-product; since "unbuffered_" has "bool"
         // elements, which convert to 0 or 1, multiplication acts as AND; since
         // "order_in_word" has distinct single-bit values, addition acts as OR
- x[ i ] = std::inner_product( order_in_word.begin(), order_in_word.end(),
- this->unbuffered_.begin() + (i * md5_digest::bits_per_word),
- self_type::iword_type(0u) );
+ words[ i ] = std::inner_product( order_in_word.begin(),
+ order_in_word.end(), &scratch[ i * md5_digest::bits_per_word ],
+ iword_type(0u) );
     }
 
     // Set up rounds
- self_type::ibuffer_type buffer = this->buffer_;
+ ibuffer_type buffer = this->buffer_;
+
+ scratch.resize( words.size() ); // repurposed!
 
     // Round 1
     {
- md5_special_op<md5_f, self_type::iword_type, md5_digest::bits_per_word>
- ff;
+ md5_special_op<md5_f, iword_type, md5_digest::bits_per_word> ff;
 
- xx = x[ skipped_indices(self_type::words_per_block, 0, 1) ];
- for ( size_t i = 0u ; i < self_type::words_per_block ; ++i )
+ scratch = words[ skipped_indices(words_per_block, 0, 1) ];
+ for ( size_t i = 0u ; i < words_per_block ; ++i )
         {
             ff( buffer[( 16u - i ) % 4u], buffer[( 17u - i ) % 4u],
- buffer[( 18u - i ) % 4u], buffer[( 19u - i ) % 4u], xx[i],
- md5_s[0][i % 4u], self_type::hashing_table[i] );
+ buffer[( 18u - i ) % 4u], buffer[( 19u - i ) % 4u], scratch[i],
+ md5_s[0][i % 4u], hashing_table[i] );
         }
     }
 
     // Round 2
     {
- md5_special_op<md5_g, self_type::iword_type, md5_digest::bits_per_word>
- gg;
+ md5_special_op<md5_g, iword_type, md5_digest::bits_per_word> gg;
 
- xx = x[ skipped_indices(self_type::words_per_block, 1, 5) ];
- for ( size_t i = 0u ; i < self_type::words_per_block ; ++i )
+ scratch = words[ skipped_indices(words_per_block, 1, 5) ];
+ for ( size_t i = 0u ; i < words_per_block ; ++i )
         {
             gg( buffer[( 16u - i ) % 4u], buffer[( 17u - i ) % 4u],
- buffer[( 18u - i ) % 4u], buffer[( 19u - i ) % 4u], xx[i],
- md5_s[1][i % 4u], self_type::hashing_table[16 + i] );
+ buffer[( 18u - i ) % 4u], buffer[( 19u - i ) % 4u], scratch[i],
+ md5_s[1][i % 4u], hashing_table[16 + i] );
         }
     }
 
     // Round 3
     {
- md5_special_op<md5_h, self_type::iword_type, md5_digest::bits_per_word>
- hh;
+ md5_special_op<md5_h, iword_type, md5_digest::bits_per_word> hh;
 
- xx = x[ skipped_indices(self_type::words_per_block, 5, 3) ];
- for ( size_t i = 0u ; i < self_type::words_per_block ; ++i )
+ scratch = words[ skipped_indices(words_per_block, 5, 3) ];
+ for ( size_t i = 0u ; i < words_per_block ; ++i )
         {
             hh( buffer[( 16u - i ) % 4u], buffer[( 17u - i ) % 4u],
- buffer[( 18u - i ) % 4u], buffer[( 19u - i ) % 4u], xx[i],
- md5_s[2][i % 4u], self_type::hashing_table[32 + i] );
+ buffer[( 18u - i ) % 4u], buffer[( 19u - i ) % 4u], scratch[i],
+ md5_s[2][i % 4u], hashing_table[32 + i] );
         }
     }
 
     // Round 4
     {
- md5_special_op<md5_i, self_type::iword_type, md5_digest::bits_per_word>
- ii;
+ md5_special_op<md5_i, iword_type, md5_digest::bits_per_word> ii;
 
- xx = x[ skipped_indices(self_type::words_per_block, 0, 7) ];
- for ( size_t i = 0u ; i < self_type::words_per_block ; ++i )
+ scratch = words[ skipped_indices(words_per_block, 0, 7) ];
+ for ( size_t i = 0u ; i < words_per_block ; ++i )
         {
             ii( buffer[( 16u - i ) % 4u], buffer[( 17u - i ) % 4u],
- buffer[( 18u - i ) % 4u], buffer[( 19u - i ) % 4u], xx[i],
- md5_s[3][i % 4u], self_type::hashing_table[48 + i] );
+ buffer[( 18u - i ) % 4u], buffer[( 19u - i ) % 4u], scratch[i],
+ md5_s[3][i % 4u], hashing_table[48 + i] );
         }
     }
 


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk