[library Boost.Hash
[authors [James, Daniel]]
[copyright 2005 Daniel James]
[purpose std::tr1 compliant hash function object]
[license
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt
)
]
]
[/ QuickBook Document version 1.0 ]
[/ Feb 8, 2005 ]
[def __note__ [$images/note.png]]
[def __alert__ [$images/alert.png]]
[def __tip__ [$images/tip.png]]
[section:intro Introduction]
[def __tr1__ [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1745.pdf
C++ Standard Library Technical Report]]
[def __tr1-short__ [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1745.pdf
Technical Report]]
[def __multi-index__ [@../../libs/multi_index/doc/index.html
Boost Multi-Index Containers Library]]
[def __multi-index-short__ [@../../libs/multi_index/doc/index.html
Boost.MultiIndex]]
[def __issues__ [@http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1756.pdf
Library Extension Technical Report Issues List]]
[def __hash-function__ [@http://en.wikipedia.org/wiki/Hash_function hash function]]
[def __hash-table__ [@http://en.wikipedia.org/wiki/Hash_table hash table]]
[classref boost::hash] is an implementation of the __hash-function__ object
specified by the __tr1__. It is intended for use as the default hash function
for unordered associative containers, and the __multi-index__'s hash indexes.
As it is compliant with the __tr1-short__, it will work with:
* integers
* floats
* pointers
* strings
It also implements the extension proposed by Peter Dimov in issue 6.18 of the
__issues__, this adds support for:
* `std::pair`
* the standard containers.
The extension also allows the user to customise the hash function for
user-defined types. Which means that you don't need to use a custom hash
function object with a container that uses [classref boost::hash] by default.
[endsect]
[section:tutorial Tutorial]
When using __multi-index-short__, you don't need to do anything, as it uses
[classref boost::hash] by default. To find out how to use a user-defined type,
read the [link section.tutorial.custom section on Extending Boost.Hash].
If your standard library supplies its own implementation of the unordered
associative containers and you wish to use
[classref boost::hash] you just supply the extra template parameter:
std::unordered_multiset, boost::hash >
set_of_ints;
std::unordered_set, boost::hash >
set_of_pairs;
std::unordered_map > map_int_to_string;
To use [classref boost::hash] directly, create an instance and call it as a function:
#include
int main()
{
boost::hash string_hash;
std::size_t h = string_hash("Hash me");
}
If you wish to make use of the extensions, you will need to include the
appropriate header (see the
[link hash.reference.specification reference documentation] for the full list).
#include
int main()
{
boost::hash > pair_hash;
std::size_t h = pair_hash(std::make_pair(1, 2));
}
Or alternatively, include `` for the full library.
For an example of generic use, here is a function to generate a vector
containing the hashes of the elements of a container:
template
std::vector get_hashes(Container const& x)
{
std::vector hashes;
std::transform(x.begin(), x.end(), std::insert_iterator(hashes),
boost::hash());
return hashes;
}
[section:custom Extending Boost.Hash for a custom data type]
[classref boost::hash] is implemented by calling the function
[funcref boost::hash_value hash_value].
The namespace isn't specified so that it can detect overloads via argument
dependant lookup. So if there is a free function `hash_value` in the same
namespace as a custom type, it will get called.
If you have a structure `library::book`, where each `book` is uniquely
defined by it's member `id`:
namespace library
{
struct book
{
int id;
std::string author;
std::string title;
// ....
};
bool operator==(book const& a, book const& b)
{
return a.id == b.id;
}
}
Then all you would need to do is write the function `library::hash_value`:
namespace library
{
std::size_t hash_value(book const& b)
{
return boost::hash_value(b.id);
}
}
And you can now use [classref boost::hash] with book:
library::book knife(3458, "Zane Grey", "The Hash Knife Outfit");
library::book dandelion(1354, "Paul J. Shanley",
"Hash & Dandelion Greens");
boost::hash book_hasher;
std::size_t knife_hash_value = book_hasher(knife);
boost::unordered_set books;
books.insert(knife);
books.insert(library::book(2443, "Lindgren, Torgny", "Hash"));
books.insert(library::book(1953, "Snyder, Bernadette M.",
"Heavenly Hash: A Tasty Mix of a Mother's Meditations"));
assert(books.find(knife) != books.end());
assert(books.find(dandelion) == books.end());
Full code for this example is at
[@../../libs/functional/hash/examples/books.cpp /libs/functional/hash/examples/books.cpp].
[blurb
When writing a hash function, first look at how the equality function works.
Objects that are equal must generate the same hash value.
When objects are not equal the should generate different hash values.
In this object equality was based just on the id, if it was based
on the objects name and author the hash function should take them into account
(how to do this is discussed in the next section).
]
[endsect]
[section:combine Combining hash values]
Say you have a point class, representing a two dimensional location:
class point
{
int x;
int y;
public:
point() : x(0), y(0) {}
point(int x, int y) : x(x), y(y) {}
bool operator==(point const& other) const
{
return x = other.x && y == other.y;
}
};
and you wish to use it as the key for an `unordered_map`. You need to
customise the hash for this structure. To do this we need to combine
the hash values for `x` and `y`. Boost.Hash supplies the function
[funcref boost::hash_combine] for this purpose:
class point
{
...
friend std::size_t hash_value(point const& p)
{
std::size_t seed = 0;
boost::hash_combine(seed, p.x);
boost::hash_combine(seed, p.y);
return seed;
}
...
};
Calls to hash_combine incrementally build the hash from the different members
of point, it can be repeatedly called for any number of elements. It calls
[funcref boost::hash_value hash_value] on the supplied element, and combines
it with the seed.
Full code for this example is at
[@../../libs/functional/hash/examples/point.cpp /libs/functional/hash/examples/point.cpp].
[blurb
'''
When using boost::hash_combine the order of the
calls matters.
std::size_t seed = 0;
boost::hash_combine(seed, 1);
boost::hash_combine(seed, 2);
results in a different seed to:
std::size_t seed = 0;
boost::hash_combine(seed, 2);
boost::hash_combine(seed, 1);
If you are calculating a hash value for data where the order of the data
doesn't matter in comparisons (e.g. a set) you will have to ensure that the
data is always supplied in the same order.
'''
]
To calculate the hash of an iterator range you can use
[funcref boost::hash_range]:
std::vector some_strings;
std::size_t hash = boost::hash_range(some_strings.begin(), some_strings.end());
[endsect]
[endsect]
[section:portability Portability]
Boost.Hash is written to be as portable as possible, but unfortunately, several
older compilers don't support argument dependent lookup (ADL) - the mechanism
used for customization. On those compilers custom overloads for hash_value
need to be declared in the boost namespace.
On a strictly standards compliant compiler, an overload defined in the
boost namespace won't be found when [classref boost::hash] is instantiated,
so for these compilers the overload should only be declared in the same
namespace as the class.
Let's say we have a simple custom type:
namespace foo
{
struct custom_type
{
int value;
friend inline std::size_t hash_value(custom_type x)
{
boost::hash hasher;
return hasher(x.value);
}
};
}
On a compliant compiler, when `hash_value` is called for this type,
it will look at the namespace inside the type and find `hash_value`
but on a compiler which doesn't support ADL `hash_value` won't be found.
So on these compilers define a member function:
#ifndef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP
friend inline std::size_t hash_value(custom_type x)
{
boost::hash hasher;
return hasher(x.value);
}
#else
std::size_t hash() const
{
boost::hash hasher;
return hasher(value);
}
#endif
which will be called from the `boost` namespace:
#ifdef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP
namespace boost
{
std::size_t hash_value(foo::custom_type x)
{
return x.hash();
}
}
#endif
Full code for this example is at
[@../../libs/functional/hash/examples/portable.cpp /libs/functional/hash/examples/portable.cpp].
[endsect]
[/ Quickbook insists on putting a paragraph around the escaped code, which
messes up the library section, so I wrap it in another section. This is no good,
but there you go. ]
[section:reference_ Reference]
'''
For the full specification, see section 6.3 of the
C++ Standard Library Technical Report
and issue 6.18 of the
Library Extension Technical Report Issues List.
Includes all the following headers.
Defines boost::hash,
the implementation for built in types and
std::string and customisation functions.
std::unary_function<T, std::size_t>
An STL compliant hash function object.
std::size_t
T const&
hash_value(val)
The call to hash_value
is always unqualified, so that custom overloads can be
found via argument dependent lookup.
Only throws if
hash_value(T) throws.
Implementation of a hash function for various types.
Should never be called directly by users, instead they should use
boost::hash, boost::hash_range
or boost::hash_combine which
call hash_value without namespace qualification so that overloads
for custom types are found via ADL.
Overloads for other types supplied in other headers.
This is an extension to TR1
std::size_t
int
std::size_t
unsigned int
std::size_t
long
std::size_t
unsigned long
std::size_t
float
std::size_t
double
std::size_t
long double
std::size_t
T*
std::size_t
std::basic_string<Ch, std::char_traits<Ch>, A> const&
int, unsigned int, long, unsigned long
v
float, double, long double, T*
An unspecified value, except that equal arguments shall yield the same
result
std::basic_string<Ch, std::char_traits<Ch>, A> const&
hash_range(v.begin(), v.end());
void
size_t &
T const &
Called repeatedly to incrementally create a hash value from
several variables.
seed ^= hash_value(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
hash_value is called without
qualification, so that overloads can be found via ADL.
This is an extension to TR1
Only throws if hash_value(T) throws.
Strong exception safety, as long as hash_value(T)
also has strong exception safety.
std::size_t
It
It
void
std::size_t&
It
It
Calculate the combined hash value of the elements of an iterator
range.
size_t seed = 0;
for(; first != last; ++first)
{
hash_combine(seed, *first);
}
return seed;
hash_range is sensitive to the order of the elements
so it wouldn't be appropriate to use this with an unordered
container.
This is an extension to TR1
Only throws if hash_value(std::iterator_traits<It>::value_type)
throws. hash_range(std::size_t&, It, It) has basic exception safety as long as
hash_value(std::iterator_traits<It>::value_type)
has basic exception safety.
Hash implementation for std::pair.
std::size_t
std::pair<A, B> const &
size_t seed = 0;
hash_combine(seed, val.first);
hash_combine(seed, val.second);
return seed;
Only throws if hash_value(A)
or hash_value(B) throws.
This is an extension to TR1
Hash implementation for std::vector.
std::size_t
std::vector<T, A> const &
hash_range(val.begin(), val.end());
Only throws if hash_value(T) throws.
This is an extension to TR1
Hash implementation for std::list.
std::size_t
std::list<T, A> const &
hash_range(val.begin(), val.end());
Only throws if hash_value(T) throws.
This is an extension to TR1
Hash implementation for std::deque.
std::size_t
std::deque<T, A> const &
hash_range(val.begin(), val.end());
Only throws if hash_value(T) throws.
This is an extension to TR1
Hash implementation for std::set and std::multiset.
std::size_t
std::set<K, C, A> const &
std::size_t
std::multiset<K, C, A> const &
hash_range(val.begin(), val.end());
Only throws if hash_value(T) throws.
This is an extension to TR1
Hash implementation for std::map and std::multimap.
std::size_t
std::map<K, T, C, A> const &
std::size_t
std::multimap<K, T, C, A> const &
hash_range(val.begin(), val.end());
Only throws if
hash_value(std::pair<K const, T>)
throws.
This is an extension to TR1
'''
[/ Remove this comment and everything goes wrong! ;) ]
[endsect]
[section:acknowledgements Acknowledgements]
This library is based on the design by Peter Dimov. During the inital development
Joaquín M López Muñoz made many useful suggestions and contributed fixes.
The original implementation came from Jeremy B. Maitin-Shepard's hash table
library, although this is a complete rewrite.
[endsect]