Update hash documentation:

Rename to Boost.Functional/Hash. Add some extra details to the library header.
Use macros to link functions & classes.
Add a note about a couple of portability issues.


[SVN r28373]
This commit is contained in:
Daniel James
2005-04-21 08:44:14 +00:00
parent c121440840
commit 8da0e01046

View File

@@ -1,7 +1,10 @@
[library Boost.Hash [library Boost.Functional/Hash
[authors [James, Daniel]] [authors [James, Daniel]]
[copyright 2005 Daniel James] [copyright 2005 Daniel James]
[purpose std::tr1 compliant hash function object] [purpose Extendible hash function object]
[category higher-order]
[id hash]
[dirname hash]
[license [license
Distributed under the Boost Software License, Version 1.0. Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at (See accompanying file LICENSE_1_0.txt or copy at
@@ -17,6 +20,10 @@
[def __note__ [$images/note.png]] [def __note__ [$images/note.png]]
[def __alert__ [$images/alert.png]] [def __alert__ [$images/alert.png]]
[def __tip__ [$images/tip.png]] [def __tip__ [$images/tip.png]]
[def __boost_hash [classref boost::hash]]
[def __hash_value [funcref boost::hash_value hash_value]]
[def __hash_combine [funcref boost::hash_combine]]
[def __hash_range [funcref boost::hash_range]]
[section:intro Introduction] [section:intro Introduction]
@@ -33,8 +40,8 @@
[def __hash-function__ [@http://en.wikipedia.org/wiki/Hash_function hash function]] [def __hash-function__ [@http://en.wikipedia.org/wiki/Hash_function hash function]]
[def __hash-table__ [@http://en.wikipedia.org/wiki/Hash_table hash table]] [def __hash-table__ [@http://en.wikipedia.org/wiki/Hash_table hash table]]
[classref boost::hash] is an implementation of the __hash-function__ object __boost_hash is an implementation of the __hash-function__ object
specified by the __tr1__. It is intended for use as the default hash function specified by the __tr1-short__. It is intended for use as the default hash function
for unordered associative containers, and the __multi-index__'s hash indexes. for unordered associative containers, and the __multi-index__'s hash indexes.
As it is compliant with the __tr1-short__, it will work with: As it is compliant with the __tr1-short__, it will work with:
@@ -50,36 +57,36 @@ __issues__, this adds support for:
* arrays * arrays
* `std::pair` * `std::pair`
* the standard containers. * the standard containers.
* extending [classref boost::hash] for custom types. * extending __boost_hash for custom types.
[endsect] [endsect]
[section:tutorial Tutorial] [section:tutorial Tutorial]
When using a hash index with __multi-index-short__, you don't need to do When using a hash index with __multi-index-short__, you don't need to do
anything to use [classref boost::hash] as it uses it by default. anything to use __boost_hash as it uses it by default.
To find out how to use a user-defined type, read the To find out how to use a user-defined type, read the
[link boost_hash.custom section on extending Boost.Hash]. [link hash.custom section on extending boost::hash].
If your standard library supplies its own implementation of the unordered If your standard library supplies its own implementation of the unordered
associative containers and you wish to use associative containers and you wish to use
[classref boost::hash], just use an extra template parameter: __boost_hash, just use an extra template parameter:
std::unordered_multiset<std::vector<int>, boost::hash<int> > std::unordered_multiset<std::vector<int>, __boost_hash<int> >
set_of_ints; set_of_ints;
std::unordered_set<std::pair<int, int>, boost::hash<std::pair<int, int> > std::unordered_set<std::pair<int, int>, __boost_hash<std::pair<int, int> >
set_of_pairs; set_of_pairs;
std::unordered_map<int, std::string, boost::hash<int> > map_int_to_string; std::unordered_map<int, std::string, __boost_hash<int> > map_int_to_string;
To use [classref boost::hash] directly, create an instance and call it as a function: To use __boost_hash directly, create an instance and call it as a function:
#include <boost/hash/hash.hpp> #include <boost/hash/hash.hpp>
int main() int main()
{ {
boost::hash<std::string> string_hash; __boost_hash<std::string> string_hash;
std::size_t h = string_hash("Hash me"); std::size_t h = string_hash("Hash me");
} }
@@ -92,7 +99,7 @@ appropriate header (see the
int main() int main()
{ {
boost::hash<std::pair<int, int> > pair_hash; __boost_hash<std::pair<int, int> > pair_hash;
std::size_t h = pair_hash(std::make_pair(1, 2)); std::size_t h = pair_hash(std::make_pair(1, 2));
} }
@@ -107,17 +114,16 @@ containing the hashes of the elements of a container:
{ {
std::vector<std::size_t> hashes; std::vector<std::size_t> hashes;
std::transform(x.begin(), x.end(), std::insert_iterator(hashes), std::transform(x.begin(), x.end(), std::insert_iterator(hashes),
boost::hash<typename Container::value_type>()); __boost_hash<typename Container::value_type>());
return hashes; return hashes;
} }
[endsect] [endsect]
[section:custom Extending Boost.Hash for a custom data type] [section:custom Extending boost::hash for a custom data type]
[classref boost::hash] is implemented by calling the function __boost_hash is implemented by calling the function __hash_value.
[funcref boost::hash_value hash_value].
The namespace isn't specified so that it can detect overloads via argument 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 dependant lookup. So if there is a free function `hash_value` in the same
namespace as a custom type, it will get called. namespace as a custom type, it will get called.
@@ -148,22 +154,22 @@ Then all you would need to do is write the function `library::hash_value`:
{ {
std::size_t hash_value(book const& b) std::size_t hash_value(book const& b)
{ {
boost::hash<int> hasher; __boost_hash<int> hasher;
return hasher(b.id); return hasher(b.id);
} }
} }
And you can now use [classref boost::hash] with book: And you can now use __boost_hash with book:
library::book knife(3458, "Zane Grey", "The Hash Knife Outfit"); library::book knife(3458, "Zane Grey", "The Hash Knife Outfit");
library::book dandelion(1354, "Paul J. Shanley", library::book dandelion(1354, "Paul J. Shanley",
"Hash & Dandelion Greens"); "Hash & Dandelion Greens");
boost::hash<library::book> book_hasher; __boost_hash<library::book> book_hasher;
std::size_t knife_hash_value = book_hasher(knife); std::size_t knife_hash_value = book_hasher(knife);
// If std::unordered_set is available: // If std::unordered_set is available:
std::unordered_set<library::book, boost::hash<library::book> > books; std::unordered_set<library::book, __boost_hash<library::book> > books;
books.insert(knife); books.insert(knife);
books.insert(library::book(2443, "Lindgren, Torgny", "Hash")); books.insert(library::book(2443, "Lindgren, Torgny", "Hash"));
books.insert(library::book(1953, "Snyder, Bernadette M.", books.insert(library::book(1953, "Snyder, Bernadette M.",
@@ -185,7 +191,6 @@ on the objects name and author the hash function should take them into account
(how to do this is discussed in the next section). (how to do this is discussed in the next section).
] ]
[endsect] [endsect]
[section:combine Combining hash values] [section:combine Combining hash values]
@@ -208,8 +213,8 @@ Say you have a point class, representing a two dimensional location:
and you wish to use it as the key for an `unordered_map`. You need to 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 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 the hash values for `x` and `y`. The function
[funcref boost::hash_combine] for this purpose: __hash_combine is supplied for this purpose:
class point class point
{ {
@@ -218,8 +223,8 @@ the hash values for `x` and `y`. Boost.Hash supplies the function
friend std::size_t hash_value(point const& p) friend std::size_t hash_value(point const& p)
{ {
std::size_t seed = 0; std::size_t seed = 0;
boost::hash_combine(seed, p.x); __hash_combine(seed, p.x);
boost::hash_combine(seed, p.y); __hash_combine(seed, p.y);
return seed; return seed;
} }
@@ -229,26 +234,25 @@ the hash values for `x` and `y`. Boost.Hash supplies the function
Calls to hash_combine incrementally build the hash from the different members 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 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 __hash_value on the supplied element, and combines it with the seed.
it with the seed.
Full code for this example is at Full code for this example is at
[@../../libs/functional/hash/examples/point.cpp /libs/functional/hash/examples/point.cpp]. [@../../libs/functional/hash/examples/point.cpp /libs/functional/hash/examples/point.cpp].
[blurb [blurb
''' '''
When using <functionname>boost::hash_combine</functionname> the order of the When using __hash_combine the order of the
calls matters. calls matters.
<programlisting> <programlisting>
std::size_t seed = 0; std::size_t seed = 0;
boost::hash_combine(seed, 1); __hash_combine(seed, 1);
boost::hash_combine(seed, 2); __hash_combine(seed, 2);
</programlisting> </programlisting>
results in a different seed to: results in a different seed to:
<programlisting> <programlisting>
std::size_t seed = 0; std::size_t seed = 0;
boost::hash_combine(seed, 2); __hash_combine(seed, 2);
boost::hash_combine(seed, 1); __hash_combine(seed, 1);
</programlisting> </programlisting>
If you are calculating a hash value for data where the order of the data 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 doesn't matter in comparisons (e.g. a set) you will have to ensure that the
@@ -256,23 +260,22 @@ data is always supplied in the same order.
''' '''
] ]
To calculate the hash of an iterator range you can use To calculate the hash of an iterator range you can use __hash_range:
[funcref boost::hash_range]:
std::vector<std::string> some_strings; std::vector<std::string> some_strings;
std::size_t hash = boost::hash_range(some_strings.begin(), some_strings.end()); std::size_t hash = __hash_range(some_strings.begin(), some_strings.end());
[endsect] [endsect]
[section:portability Portability] [section:portability Portability]
Boost.Hash is written to be as portable as possible, but unfortunately, several __boost_hash is written to be as portable as possible, but unfortunately, several
older compilers don't support argument dependent lookup (ADL) - the mechanism older compilers don't support argument dependent lookup (ADL) - the mechanism
used for customization. On those compilers custom overloads for hash_value used for customization. On those compilers custom overloads for hash_value
need to be declared in the boost namespace. need to be declared in the boost namespace.
On a strictly standards compliant compiler, an overload defined in the On a strictly standards compliant compiler, an overload defined in the
boost namespace won't be found when [classref boost::hash] is instantiated, boost namespace won't be found when __boost_hash is instantiated,
so for these compilers the overload should only be declared in the same so for these compilers the overload should only be declared in the same
namespace as the class. namespace as the class.
@@ -286,7 +289,7 @@ Let's say we have a simple custom type:
friend inline std::size_t hash_value(custom_type x) friend inline std::size_t hash_value(custom_type x)
{ {
boost::hash<int> hasher; __boost_hash<int> hasher;
return hasher(x.value); return hasher(x.value);
} }
}; };
@@ -301,13 +304,13 @@ So on these compilers define a member function:
#ifndef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP #ifndef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP
friend inline std::size_t hash_value(custom_type x) friend inline std::size_t hash_value(custom_type x)
{ {
boost::hash<int> hasher; __boost_hash<int> hasher;
return hasher(x.value); return hasher(x.value);
} }
#else #else
std::size_t hash() const std::size_t hash() const
{ {
boost::hash<int> hasher; __boost_hash<int> hasher;
return hasher(value); return hasher(value);
} }
#endif #endif
@@ -327,6 +330,16 @@ which will be called from the `boost` namespace:
Full code for this example is at Full code for this example is at
[@../../libs/functional/hash/examples/portable.cpp /libs/functional/hash/examples/portable.cpp]. [@../../libs/functional/hash/examples/portable.cpp /libs/functional/hash/examples/portable.cpp].
[h2 Other Issues]
On Visual C++ versions 6.5 and 7.0, `hash_value` isn't overloaded for built in
arrays. __boost_hash, __hash_combine and __hash_range all use a workaround to
support built in arrays so this shouldn't be a problem in most cases.
`boost::hash_value(long double)` on GCC on Solaris appears to treat
`long double`s as doubles - so the hash function doesn't take into account the
full range of values.
[endsect] [endsect]
[/ Quickbook insists on putting a paragraph around the escaped code, which [/ Quickbook insists on putting a paragraph around the escaped code, which