diff --git a/doc/comparison.qbk b/doc/comparison.qbk
new file mode 100644
index 00000000..7c94da57
--- /dev/null
+++ b/doc/comparison.qbk
@@ -0,0 +1,162 @@
+[/ Copyright 2006-2007 Daniel James.
+ / 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) ]
+
+[section:comparison Comparison with Associative Containers]
+
+[table Interface differences.
+ [[Associative Containers] [Unordered Associative Containers]]
+
+ [
+ [Parameterized by an ordering relation `Compare`]
+ [Parameterized by a function object `Hash` and an equivalence relation
+ `Pred`]
+ ]
+ [
+ [`Compare` exposed by member typedef `key_compare`, accessed by member function `key_comp()`]
+ [`Hash` exposed by member typedef `hasher`, accessed by member function `hash_function()`.\n`Pred` by member typedef `key_equal` and member function `key_eq()`.]
+ ]
+ [
+ [Member typedef `value_compare` supplies an ordering comparison for member elements, accessed by member function `value_comp()`.]
+ [No equivalent. No idea why.]
+ ]
+ [/TODO: Mention a range? This is meant to be differences but this doesn't
+ seem to be complete.]
+ [
+ [Constructors have optional extra parameters for the comparison object.]
+ [Constructors have optional extra parameters for the initial minimum
+ number of buckets, a hash function and an equality object.]
+ ]
+
+ [
+ [Keys `k1`, `k2` are considered equivalent if
+ `!Compare(k1, k2) && !Compare(k2, k1)`]
+ [Keys `k1`, `k2` are considered equivalent if `Pred(k1, k2)`]
+ ]
+ [
+ [Member function `lower_bound(k)` and `upper_bound(k)`]
+ [No equivalent. Since the elements aren't ordered `lower_bound` and
+ `upper_bound` would be meaningless.]
+ ]
+ [
+ [`equal_range(k)` returns an empty range at the position that k
+ would be inserted if k isn't present in the container.]
+ [`equal_range(k)` returns a range at the end of the container if
+ k isn't present in the container. It can't return a positioned
+ range as k could be inserted into multiple place. To find out the
+ bucket that k would be inserted into use `bucket(k)`. But remember
+ that an insert can cause the container to rehash - meaning that the
+ element can be inserted into a different bucket.]
+ ]
+ [
+ [`iterator`, `const_iterator` are of the biderctional category.]
+ [`iterator`, `const_iterator` are of at least the forward category.]
+ ]
+ [
+ [Inserts do not invalidate iterators or references to the container.]
+ [Inserts can invalidate iterators but not references to the container.]
+ ]
+ [
+ [Iterators iterate through the container in the order defined by
+ the comparison object.]
+ [Iterators iterate through the container in an arbitrary order, that
+ can change as elements are inserted. Although, equivalent elements
+ are always adjacent.]
+ ]
+ [
+ [No equivalent]
+ [Local iterators can be used to iterate through individual buckets.
+ (I don't think that the order of local iterators and iterators are
+ required to have any correspondence.)]
+ ]
+ [
+ [Can be compared using the `==`, `!=`, `<`, `<=`, `>`, `>=` operators]
+ [No comparison operators are defined]
+ ]
+ [
+ []
+ [When inserting with a hint, implementations are permitted to ignore
+ the hint.]
+ ]
+ [
+ [`erase` never throws an exception]
+ [The containers hash or predicate function can throw exceptions
+ from `erase`]
+ ]
+]
+
+[table Complexity Guarantees
+ [[Operation] [Associative Containers] [Unordered Associative Containers]]
+ [
+ [Construction of empty container]
+ [constant]
+ [/TODO: Do I meet this?]
+ [O(/n/) where /n/ is the minimum number of buckets.]
+ ]
+ [
+ [Construction of container from a range of /N/ elements]
+ [O(/N/ log /N/), O(/N/) if the range is sorted with `value_comp()`]
+ [Average case O(/N/), worst case
+ O(/N/'''2''')]
+ ]
+ [
+ [Insert a single element]
+ [logarithmic]
+ [Average case constant, worst case linear]
+ ]
+ [
+ [Insert a single element with a hint]
+ [Amortized constant if t elements inserted right after hint,
+ logarithmic otherwise]
+ [Average case constant, worst case linear (ie. the same as
+ a normal insert).]
+ ]
+ [
+ [Inserting a range of /N/ elements]
+ [/N/ log(`size()`+/N/)]
+ [Average case O(/N/), worst case O(/N/ * 'size()')]
+ ]
+ [
+ [Erase by key, `k`]
+ [O(log(`size()`) + `count(k)`)]
+ [Average case: O(`count(k)`), Worst case: O(`size()`)]
+ ]
+ [
+ [Erase a single element by iterator]
+ [Amortized constant]
+ [Average case: O(1), Worst case: O(`size()`)]
+ ]
+ [
+ [Erase a range of /N/ elements]
+ [O(log(`size()`) + /N/)]
+ [Average case: O(/N/), Worst case: O(`size()`)]
+ ]
+ [
+ [Clearing the container]
+ [O(`size()`)]
+ [O(`size()`)]
+ ]
+ [
+ [Find]
+ [logarithmic]
+ [Average case: O(/N/), Worst case: O(`size()`)]
+ ]
+ [/ TODO: Average case is probably wrong. ]
+ [
+ [Count]
+ [O(log(`size()`) + `count(k)`)]
+ [Average case: O(1), Worst case: O(`size()`)]
+ ]
+ [
+ [`equal_range(k)`]
+ [logarithmic]
+ [Average case: O(`count(k)`), Worst case: O(`size()`)]
+ ]
+ [
+ [`lower_bound`,`upper_bound`]
+ [logarithmic]
+ [n/a]
+ ]
+]
+
+[endsect]
diff --git a/doc/hash_equality.qbk b/doc/hash_equality.qbk
new file mode 100644
index 00000000..4a24eefe
--- /dev/null
+++ b/doc/hash_equality.qbk
@@ -0,0 +1,140 @@
+[/ Copyright 2006-2007 Daniel James.
+ / 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) ]
+
+[section:hash_equality Equality Predicates and Hash Functions]
+
+[/TODO: A better introduction to hash functions?]
+
+While the associative containers use an ordering relation to specify how the
+elements are stored, the unordered associative containers use an equality
+predicate and a hash function. For example [classref boost::unordered_set]
+is declared as:
+
+ template,
+ typename Pred = std::equal_to,
+ typename Alloc = std::allocator >
+ class ``[classref boost::unordered_set unordered_set]``;
+
+The hash function comes first as you might want to change the hash function
+but not the equality predicate, while if you were to change the behaviour
+of the equality predicate you would have to change the hash function to match
+it.
+
+For example, if you wanted to use the
+[@http://www.isthe.com/chongo/tech/comp/fnv/ FNV-1 hash] you could write:
+
+ ``[classref boost::unordered_set]`` words;
+
+An example implementation of FNV-1, and some other hash functions are supplied
+in the examples directory.
+
+Alternatively, you might wish to use a different equality function. If so, make
+sure you use a hash function that matches it. For example, a
+case-insensitive dictionary:
+
+ struct iequal_to
+ : std::binary_function
+ {
+ bool operator()(std::string const& x,
+ std::string const& y) const
+ {
+ return boost::algorithm::iequals(x, y);
+ }
+ };
+
+ struct ihash
+ : std::unary_function
+ {
+ bool operator()(std::string const& x) const
+ {
+ std::size_t seed = 0;
+
+ for(std::string::const_iterator it = x.begin();
+ it != x.end(); ++it)
+ {
+ boost::hash_combine(seed, std::toupper(*it));
+ }
+
+ return seed;
+ }
+ };
+
+ struct word_info;
+
+ boost::unordered_map
+ idictionary;
+
+A more generic version of this example is available at:
+[@../../libs/unordered/examples/case_insensitive.hpp /libs/unordered/examples/case_insensitive.hpp]
+
+[h2 Custom Types]
+
+Similarly, a custom hash function can be used for custom types:
+
+ struct point {
+ int x;
+ int y;
+ };
+
+ bool operator==(point const& p1, point const& p2)
+ {
+ return p1.x == p2.x && p1.y == p2.y;
+ }
+
+ struct point_hash
+ : std::unary_function
+ {
+ std::size_t operator()(point const& p) const
+ {
+ std::size_t seed = 0;
+ boost::hash_combine(seed, p.x);
+ boost::hash_combine(seed, p.y);
+ return seed;
+ }
+ }
+
+ boost::unordered_multiset, point_hash>
+ points;
+
+Although, customizing Boost.Hash is probably a better solution:
+
+ struct point {
+ int x;
+ int y;
+ };
+
+ bool operator==(point const& p1, point const& p2)
+ {
+ return p1.x == p2.x && p1.y == p2.y;
+ }
+
+ std::size_t hash_value(point const& x) {
+ std::size_t seed = 0;
+ boost::hash_combine(seed, p.x);
+ boost::hash_combine(seed, p.y);
+ return seed;
+ }
+
+ // Now the default functions work.
+ boost::unordered_multiset points;
+
+See the Boost.Hash documentation for more detail on how to do this. Remember
+that it relies on extensions to the draft standard - so it won't work on other
+implementations of the unordered associative containers.
+
+[table Methods for accessing the hash and equality functions.
+ [[Method] [Description]]
+
+ [
+ [``hasher hash_function() const``]
+ [Returns the container's hash function.]
+ ]
+ [
+ [``key_equal key_eq() const``]
+ [Returns the container's key equality function.]
+ ]
+]
+
+[endsect]