On Thu, Jul 24, 2014 at 02:00:24AM +0200, Oleg Endo wrote:
> On Wed, 2014-07-23 at 11:37 +0200, Richard Biener wrote:
> > On Fri, Jul 18, 2014 at 3:08 AM, Trevor Saunders <tsaund...@mozilla.com> 
> > wrote:
> > > On Thu, Jul 17, 2014 at 06:36:31AM +0200, Andi Kleen wrote:
> > >> On Wed, Jul 16, 2014 at 10:40:53PM -0400, Trevor Saunders wrote:
> > >> >
> > >> > > + public:
> > >> > > +
> > >> > > +  /* Start incremential hashing, optionally with SEED.  */
> > >> > > +  void begin (hashval_t seed = 0)
> > >> > > +  {
> > >> > > +    val = seed;
> > >> >
> > >> > why isn't this the ctor?
> > >>
> > >> It's standard for hash classes to have explicit begin()/end().
> > >> All the existing ones I've seen work this way.
> > >
> > >  I only know of one vaguelly similar thing
> > >  http://mxr.mozilla.org/mozilla-central/source/mfbt/SHA1.h#37  which
> > >  doesn't do that, and a bunch of people doing something doesn't
> > >  necessarily mean it makes sense.  Now there may be a good reason it
> > >  does make sense, but unless these other people need begin() to be
> > >  fallible I don't see it.
> > 
> > I agree with Trevor here.  Please make begin() the constructor.
> > Btw, what will be the way to plug in an alternative hash function?
> > That is, there doesn't seem to be a separation of interface
> > and implementation in your patch (like with a template or a base-class
> > you inherit from).
> 
> Isn't that what boost / std hash is actually doing?  Maybe something
> like the attached example could be an improvement?

I don't really see why that makes it any easier to plug in a different
hash algorithm

> As with boost / std hash, the hash function is a template functor that
> can be specialized on various types.  The 'incremental_hash' simply
> plugs together a hash value combiner and a hash function.  Types that
> are not implemented by the hash function (in this example) are caught at
> compile time, since implicit conversions do not take place.  However, it
> should also possible to write hash functions with a bunch of operator ()
> overloads to utilize implicit conversions.

at that point it seems like its simpler and equivelent to just overload
a global function.

> One advantage of this construct is that new types can be added along
> with hash function specializations, without the need to touch any of the
> existing hashing facilities.
> 
> I don't know how/whether this would fit with the already existing hash
> map stuff (hash-table.h, hash-map.h).  It seems those don't support user
> specified hash functions.

they do, see e.g. graphite-htab.h

Trev

> 
> Cheers,
> Oleg
> 

> typedef unsigned int hashval_t;
> typedef long long HOST_WIDE_INT;
> typedef unsigned int size_t;
> 
> // -----------------------------
> // hash function and some specializations
> 
> struct raw_data
> {
>   const void* data;
>   size_t len;
> 
>   raw_data (const void* d, size_t l) : data (d), len (l) { }
> 
>   template <typename T>
>   explicit raw_data (const T& val) : data (&val), len (sizeof (T)) { }
> };
> 
> template <typename T> struct my_hash;
> 
> template <> struct my_hash<unsigned int>
> {
>   hashval_t operator () (unsigned int val);
> };
> 
> template <> struct my_hash<HOST_WIDE_INT>
> {
>   hashval_t operator () (HOST_WIDE_INT val);
> };
> 
> template <> struct my_hash<raw_data>
> {
>   hashval_t operator () (raw_data val);
> };
> 
> template <> struct my_hash<const void*>
> {
>   hashval_t operator () (const void* val);
> };
> 
> template <typename T> struct my_hash<T*>
> {
>   hashval_t operator () (T* val)
>   {
>     return my_hash<const void*> () (val);
>   }
> };
> 
> template <typename T> struct my_hash<const T*>
> {
>   hashval_t operator () (const T* val)
>   {
>     return my_hash<const void*> () (val);
>   }
> };
> 
> // -----------------------------
> // a possible hash combiner
> struct my_hash_combiner
> {
>   hashval_t operator () (hashval_t a, hashval_t b);
> };
> 
> 
> // -----------------------------
> // generic incremental hash
> 
> template <template<typename> class HashFunction, class HashValueCombiner>
> class incremental_hash
> {
> public:
>   incremental_hash (void) : m_value (0) { }
>   incremental_hash (hashval_t seed) : m_value (seed) { }
> 
>   hashval_t value (void) const { return m_value; }
> 
>   template <typename T> incremental_hash& add (const T& val)
>   {
>     m_value = HashValueCombiner () (m_value, HashFunction<T> () (val));
>     return *this;
>   }
> 
> private:
>   hashval_t m_value;
> };
> 
> // hash function of an incremental_hash is its current value, regardless
> // of the actual hash function used.
> template <template<typename> class Func, class Combiner>
> struct my_hash< incremental_hash<Func, Combiner> >
> {
>   hashval_t operator () (const incremental_hash<Func, Combiner>& val)
>   {
>     return val.value ();
>   }
> };
> 
> 
> // -----------------------------
> // use case
> 
> struct my_object
> {
>   int a, b, c, d;
> };
> 
> typedef incremental_hash<my_hash, my_hash_combiner> my_inc_hash;
> 
> int main (int argc, const char* argv[])
> {
>   my_object some_obj;
> 
>   my_inc_hash hash;
> 
>   hash.add (5U)
>       .add<unsigned int> (234)     // explicit hash func, implicit conversion.
>       .add (HOST_WIDE_INT (2135))
>       .add (raw_data (argv, argc)) // raw data hash
>       .add (raw_data (some_obj))   // iterative_hash_object macro
>       .add (argv)                  // pointer hash
>       .add (argv[0]);              // pointer hash
> 
>   my_inc_hash hash2 (0x5533);
>   hash2.add (123U)
>        .add (hash);  // 'merge' two incremental hashes.
> 
>   return hash2.value ();
> }

Reply via email to