1 2[/ Copyright 2005-2008 Daniel James. 3 / Distributed under the Boost Software License, Version 1.0. (See accompanying 4 / file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ] 5 6[quickbook 1.7] 7[import samples/tutorial.cpp] 8 9[def __multi-index-short__ [@boost:/libs/multi_index/doc/index.html 10 Boost.MultiIndex]] 11 12[section:tutorial Tutorial] 13 14When using a hash index with __multi-index-short__, you don't need to do 15anything to use [classref boost::hash] as it uses it by default. 16To find out how to use a user-defined type, read the 17[link hash.custom section on extending boost::hash for a custom data type]. 18 19If your standard library supplies its own implementation of the unordered 20associative containers and you wish to use 21[classref boost::hash], just use an extra template parameter: 22 23 std::unordered_multiset<int, ``[classref boost::hash]``<int> > 24 set_of_ints; 25 26 std::unordered_set<std::pair<int, int>, ``[classref boost::hash]``<std::pair<int, int> > 27 set_of_pairs; 28 29 std::unordered_map<int, std::string, ``[classref boost::hash]``<int> > map_int_to_string; 30 31To use [classref boost::hash] directly, create an instance and call it as a function: 32 33 #include <``[headerref boost/container_hash/hash.hpp]``> 34 35 int main() 36 { 37 ``[classref boost::hash]``<std::string> string_hash; 38 39 std::size_t h = string_hash("Hash me"); 40 } 41 42For an example of generic use, here is a function to generate a vector 43containing the hashes of the elements of a container: 44 45[get_hashes] 46 47[endsect] 48 49[section:custom Extending boost::hash for a custom data type] 50 51[classref boost::hash] is implemented by calling the function 52[funcref boost::hash_value hash_value]. 53The namespace isn't specified so that it can detect overloads via argument 54dependant lookup. So if there is a free function `hash_value` in the same 55namespace as a custom type, it will get called. 56 57If you have a structure `library::book`, where each `book` is uniquely 58defined by it's member `id`: 59 60 namespace library 61 { 62 struct book 63 { 64 int id; 65 std::string author; 66 std::string title; 67 68 // .... 69 }; 70 71 bool operator==(book const& a, book const& b) 72 { 73 return a.id == b.id; 74 } 75 } 76 77Then all you would need to do is write the function `library::hash_value`: 78 79 namespace library 80 { 81 std::size_t hash_value(book const& b) 82 { 83 ``[classref boost::hash]``<int> hasher; 84 return hasher(b.id); 85 } 86 } 87 88And you can now use [classref boost::hash] with book: 89 90 library::book knife(3458, "Zane Grey", "The Hash Knife Outfit"); 91 library::book dandelion(1354, "Paul J. Shanley", 92 "Hash & Dandelion Greens"); 93 94 ``[classref boost::hash]``<library::book> book_hasher; 95 std::size_t knife_hash_value = book_hasher(knife); 96 97 // If std::unordered_set is available: 98 std::unordered_set<library::book, ``[classref boost::hash]``<library::book> > books; 99 books.insert(knife); 100 books.insert(library::book(2443, "Lindgren, Torgny", "Hash")); 101 books.insert(library::book(1953, "Snyder, Bernadette M.", 102 "Heavenly Hash: A Tasty Mix of a Mother's Meditations")); 103 104 assert(books.find(knife) != books.end()); 105 assert(books.find(dandelion) == books.end()); 106 107The full example can be found in: 108[@boost:/libs/container_hash/examples/books.hpp /libs/container_hash/examples/books.hpp] 109and 110[@boost:/libs/container_hash/examples/books.cpp /libs/container_hash/examples/books.cpp]. 111 112[tip 113When writing a hash function, first look at how the equality function works. 114Objects that are equal must generate the same hash value. 115When objects are not equal they should generate different hash values. 116In this object equality was based just on the id so the hash function 117only hashes the id. If it was based on the object's name and author 118then the hash function should take them into account 119(how to do this is discussed in the next section). 120] 121 122[endsect] 123 124[section:combine Combining hash values] 125 126Say you have a point class, representing a two dimensional location: 127 128 class point 129 { 130 int x; 131 int y; 132 public: 133 point() : x(0), y(0) {} 134 point(int x, int y) : x(x), y(y) {} 135 136 bool operator==(point const& other) const 137 { 138 return x == other.x && y == other.y; 139 } 140 }; 141 142and you wish to use it as the key for an `unordered_map`. You need to 143customise the hash for this structure. To do this we need to combine 144the hash values for `x` and `y`. The function 145[funcref boost::hash_combine] is supplied for this purpose: 146 147 class point 148 { 149 ... 150 151 friend std::size_t hash_value(point const& p) 152 { 153 std::size_t seed = 0; 154 ``[funcref boost::hash_combine]``(seed, p.x); 155 ``[funcref boost::hash_combine]``(seed, p.y); 156 157 return seed; 158 } 159 160 ... 161 }; 162 163Calls to hash_combine incrementally build the hash from the different members 164of point, it can be repeatedly called for any number of elements. It calls 165[funcref boost::hash_value hash_value] on the supplied element, and combines it with the seed. 166 167Full code for this example is at 168[@boost:/libs/container_hash/examples/point.cpp /libs/container_hash/examples/point.cpp]. 169 170[note 171When using [funcref boost::hash_combine] the order of the 172calls matters. 173''' 174<programlisting> 175 std::size_t seed = 0; 176 boost::hash_combine(seed, 1); 177 boost::hash_combine(seed, 2); 178</programlisting> 179results in a different seed to: 180<programlisting> 181 std::size_t seed = 0; 182 boost::hash_combine(seed, 2); 183 boost::hash_combine(seed, 1); 184</programlisting> 185''' 186If you are calculating a hash value for data where the order of the data 187doesn't matter in comparisons (e.g. a set) you will have to ensure that the 188data is always supplied in the same order. 189] 190 191To calculate the hash of an iterator range you can use [funcref boost::hash_range]: 192 193 std::vector<std::string> some_strings; 194 std::size_t hash = ``[funcref boost::hash_range]``(some_strings.begin(), some_strings.end()); 195 196Note that when writing template classes, you might not want to include the main 197hash header as it's quite an expensive include that brings in a lot of other 198headers, so instead you can include the `<boost/container_hash/hash_fwd.hpp>` 199header which forward declares [classref boost::hash], 200[funcref boost::hash_range] and [funcref boost::hash_combine]. You'll need to 201include the main header before instantiating [classref boost::hash]. When using 202a container that uses [classref boost::hash] it should do that for you, so your 203type will work fine with the boost hash containers. There's an example of this 204in [@boost:/libs/container_hash/examples/template.hpp template.hpp] and 205[@boost:/libs/container_hash/examples/template.cpp template.cpp]. 206 207[endsect] 208