• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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