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]