[library Boost.Functional/Hash [quickbook 1.3] [authors [James, Daniel]] [copyright 2005 Daniel James] [purpose A TR1 hash function object that can be extended to hash user defined types] [category higher-order] [id hash] [dirname hash] [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] ] ] [def __note__ [$images/note.png]] [def __alert__ [$images/alert.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] [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]] __boost_hash is an implementation of the __hash-function__ object 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. 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: * arrays * `std::pair` * the standard containers. * extending __boost_hash for custom types. [endsect] [section:tutorial Tutorial] When using a hash index with __multi-index-short__, you don't need to do anything to use __boost_hash as it uses it by default. To find out how to use a user-defined type, read the [link hash.custom section on extending boost::hash for a custom data type]. If your standard library supplies its own implementation of the unordered associative containers and you wish to use __boost_hash, just use an 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 __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"); } 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; } [endsect] [section:custom Extending boost::hash for a custom data type] __boost_hash is implemented by calling the function __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) { __boost_hash hasher; return hasher(b.id); } } And you can now use __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); // If std::unordered_set is available: std::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()); The full example can be found in: [@../../libs/functional/hash/examples/books.cpp /libs/functional/hash/examples/books.hpp] and [@../../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`. The function __hash_combine is supplied for this purpose: class point { ... friend std::size_t hash_value(point const& p) { std::size_t seed = 0; __hash_combine(seed, p.x); __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 __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 __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 __hash_range: std::vector some_strings; std::size_t hash = __hash_range(some_strings.begin(), some_strings.end()); [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 __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 { template class custom_type { T value; public: custom_type(T x) : value(x) {} friend 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. To make things worse, some compilers which do support ADL won't find a friend class defined inside the class. So first move the member function out of the class: namespace foo { template class custom_type { T value; public: custom_type(T x) : value(x) {} std::size_t hash(custom_type x) { __boost_hash hasher; return hasher(value); } }; template inline std::size_t hash_value(custom_type x) { return x.hash(); } } Unfortunately, I couldn't declare hash_value as a friend, as some compilers don't support template friends, so instead I declared a member function to calculate the hash, can called it from hash_value. For compilers which don't support ADL, hash_value needs to be defined in the boost namespace: #ifdef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP namespace boost #else namespace foo #endif { template std::size_t hash_value(foo::custom_type x) { return x.hash(); } } Full code for this example is at [@../../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. On Visual C++ versions 6.5 and 7.0, function pointers aren't currently supported. When using GCC on Solaris, `boost::hash_value(long double)` treats `long double`s as doubles - so the hash function doesn't take into account the full range of values. [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.
Defines boost::hash, and helper 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 unqualified, so that custom overloads can be found via argument dependent lookup. Only throws if hash_value(T) throws. 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. For the two argument overload: size_t seed = 0; for(; first != last; ++first) { hash_combine(seed, *first); } return seed; For the three arguments overload: for(; first != last; ++first) { hash_combine(seed, *first); } 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. Implementation of a hash function for integers. Generally shouldn't 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 val Implementation of a hash function for floating point values. Generally shouldn't 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 float std::size_t double std::size_t long double An unspecified value, except that equal arguments shall yield the same result Implementation of a hash function for pointers. Generally shouldn't 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 T* const& An unspecified value, except that equal arguments shall yield the same result Implementation of a hash function for built in arrays. Generally shouldn't 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 T (&val)[N] std::size_t const T (&val)[N] hash_range(val, val+N) Implementation of a hash function for std::basic_string. Generally shouldn't 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 std::basic_string<Ch, std::char_traits<Ch>, A> const& hash_range(val.begin(), val.end()) 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 std::size_t std::vector<T, A> const & std::size_t std::list<T, A> const & std::size_t std::deque<T, A> const & std::size_t std::set<K, C, A> const & std::size_t std::multiset<K, C, A> const & 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(T) throws. This is an extension to TR1
''' [/ Remove this comment and everything goes wrong! ;) ] [endsect] [section:links Links] [*A Proposal to Add Hash Tables to the Standard Library]\n [@http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2003/n1456.html]\n The hash table proposal explains much of the design. The hash function object is discussed in Section D. [*The C++ Standard Library Technical Report.]\n [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1836.pdf]\n Contains the hash function specification in section 6.3.2. [*Library Extension Technical Report Issues List.]\n [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1837.pdf]\n The library implements the extension described in Issue 6.18, pages 63-67. [*Methods for Identifying Versioned and Plagiarised Documents]\n Timothy C. Hoad, Justin Zobel\n [@http://www.cs.rmit.edu.au/~jz/fulltext/jasist-tch.pdf]\n Contains the hash function that __hash_combine is based on. [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 review was managed by Thorsten Ottosen, and the library reviewed by: David Abrahams, Alberto Barbati, Topher Cooper, Caleb Epstein, Dave Harris, Chris Jefferson, Bronek Kozicki, John Maddock, Tobias Swinger,Jaap Suter and Rob Stewart. The implementation of the hash function for pointers is based on suggestions made by Alberto Barbati and Dave Harris. Dave Harris also suggested an important improvement to __hash_combine that was taken up. The original implementation came from Jeremy B. Maitin-Shepard's hash table library, although this is a complete rewrite. [endsect]