# Boost Users :

Subject: Re: [Boost-users] Is MultiIndex right for me?
From: Daniel James (daniel_at_[hidden])
Date: 2013-07-23 17:42:22

On Tue, 23 Jul 2013, at 10:10 AM, Sensei wrote:
> On 7/22/13 7:47pm, Daniel James wrote:
> > You can use a custom hash function. Here's an example. I made the modulo
> > dynamic, but if it's a compile time constant, then the container will be
> > a tad bit smaller, and you won't need to pass the hash function and
> > equality predicate as parameters.
>
>
> Thanks Daniel. I have a question, though. Forgive me if I'm being too
> naive, but I'm trying to understand what's going on here! :)
>
> The code you posted seems to be bound at compile time to the integer p
> chosen as modulus (i.e., 53).

The modulus is bound at construction, you can also overwrite it by
assignment or swapping.

> How can I, for instance, find all values that are equal modulo 2 now,
> without instantiating another unordered_map? Finding elements modulo p,
> with p given at runtime, is the "something" I'm trying to do here :)

Currently, you'd need to create a new unordered_multimap, e.g.

typedef std::unordered_multimap<int, int, modulo_hash,
modulo_equals>
multimap;

multimap x1(0, modulo_hash(2), modulo_equals(2));

// Insert some values into x1 here.
// ....

// Copy elements into new container using a different modulo:
multimap x2(x1.begin(), x1.end(), x1.bucket_count(),
modulo_hash(p), modulo_equals(p));

// Can now swap x1 and x2 to get the newly hashed values in x1:
x1.swap(x2);

By the way, that '0' and 'x1.bucket_count()' specify the minimum number
of buckets to create.

I could possibly extend the boost implementation to allow you to change
the hash and equal functions (they'd have to have the same type, but
could have different values). It would have to rehash all the nodes, but
would avoid having to allocate any new one. So the example becomes:

typedef boost::unordered_multimap<int, int, modulo_hash,
modulo_equals>
multimap;

multimap x1(0, modulo_hash(2), modulo_equals(2));

// Insert some values into x1 here.
// ....

x1.set_hash_and_equals(modulo_hash(p), modulo_equals(p));

> The reason I was looking into MultiIndex is this: decoupling the hashing
> from the actual "equal" predicate.

You can't decouple the hash and the equal predicate - they must always
match. I suppose using a modulo hash and normal equality is sort of
okay, since you will get equal hash values for equal elements, but you
might get very poor performance and you won't be able to assume that
unequal hash values will map to different buckets - even if the number
of buckets is greater than the number of hash values.