tutorial.qbk 6.7 KB

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