forked from boostorg/unordered
219 lines
6.3 KiB
Plaintext
219 lines
6.3 KiB
Plaintext
[#intro]
|
|
= Introduction
|
|
|
|
:idprefix: intro_
|
|
:cpp: C++
|
|
|
|
For accessing data based on key lookup, the {cpp} standard library offers `std::set`,
|
|
`std::map`, `std::multiset` and `std::multimap`. These are generally
|
|
implemented using balanced binary trees so that lookup time has
|
|
logarithmic complexity. That is generally okay, but in many cases a
|
|
link:https://en.wikipedia.org/wiki/Hash_table[hash table^] can perform better, as accessing data has constant complexity,
|
|
on average. The worst case complexity is linear, but that occurs rarely and
|
|
with some care, can be avoided.
|
|
|
|
Also, the existing containers require a 'less than' comparison object
|
|
to order their elements. For some data types this is impossible to implement
|
|
or isn't practical. In contrast, a hash table only needs an equality function
|
|
and a hash function for the key.
|
|
|
|
With this in mind, unordered associative containers were added to the {cpp}
|
|
standard. Boost.Unordered provides an implementation of the containers described in {cpp}11,
|
|
with some <<compliance,deviations from the standard>> in
|
|
order to work with non-{cpp}11 compilers and libraries.
|
|
|
|
`unordered_set` and `unordered_multiset` are defined in the header
|
|
`<boost/unordered/unordered_set.hpp>`
|
|
[source,c++]
|
|
----
|
|
namespace boost {
|
|
template <
|
|
class Key,
|
|
class Hash = boost::hash<Key>,
|
|
class Pred = std::equal_to<Key>,
|
|
class Alloc = std::allocator<Key> >
|
|
class unordered_set;
|
|
|
|
template<
|
|
class Key,
|
|
class Hash = boost::hash<Key>,
|
|
class Pred = std::equal_to<Key>,
|
|
class Alloc = std::allocator<Key> >
|
|
class unordered_multiset;
|
|
}
|
|
----
|
|
|
|
`unordered_map` and `unordered_multimap` are defined in the header
|
|
`<boost/unordered/unordered_map.hpp>`
|
|
|
|
[source,c++]
|
|
----
|
|
namespace boost {
|
|
template <
|
|
class Key, class Mapped,
|
|
class Hash = boost::hash<Key>,
|
|
class Pred = std::equal_to<Key>,
|
|
class Alloc = std::allocator<std::pair<Key const, Mapped> > >
|
|
class unordered_map;
|
|
|
|
template<
|
|
class Key, class Mapped,
|
|
class Hash = boost::hash<Key>,
|
|
class Pred = std::equal_to<Key>,
|
|
class Alloc = std::allocator<std::pair<Key const, Mapped> > >
|
|
class unordered_multimap;
|
|
}
|
|
----
|
|
|
|
These containers, and all other implementations of standard unordered associative
|
|
containers, use an approach to its internal data structure design called
|
|
*closed addressing*. Starting in Boost 1.81, Boost.Unordered also provides containers
|
|
`boost::unordered_flat_set` and `boost::unordered_flat_map`, which use a
|
|
different data structure strategy commonly known as *open addressing* and depart in
|
|
a small number of ways from the standard so as to offer much better performance
|
|
in exchange (more than 2 times faster in typical scenarios):
|
|
|
|
|
|
[source,c++]
|
|
----
|
|
// #include <boost/unordered/unordered_flat_set.hpp>
|
|
//
|
|
// Note: no multiset version
|
|
|
|
namespace boost {
|
|
template <
|
|
class Key,
|
|
class Hash = boost::hash<Key>,
|
|
class Pred = std::equal_to<Key>,
|
|
class Alloc = std::allocator<Key> >
|
|
class unordered_flat_set;
|
|
}
|
|
----
|
|
|
|
[source,c++]
|
|
----
|
|
// #include <boost/unordered/unordered_flat_map.hpp>
|
|
//
|
|
// Note: no multimap version
|
|
|
|
namespace boost {
|
|
template <
|
|
class Key, class Mapped,
|
|
class Hash = boost::hash<Key>,
|
|
class Pred = std::equal_to<Key>,
|
|
class Alloc = std::allocator<std::pair<Key const, Mapped> > >
|
|
class unordered_flat_map;
|
|
}
|
|
----
|
|
|
|
Starting in Boost 1.82, the containers `boost::unordered_node_set` and `boost::unordered_node_map`
|
|
are introduced: they use open addressing like `boost::unordered_flat_set` and `boost::unordered_flat_map`,
|
|
but internally store element _nodes_, like `boost::unordered_set` and `boost::unordered_map`,
|
|
which provide stability of pointers and references to the elements:
|
|
|
|
[source,c++]
|
|
----
|
|
// #include <boost/unordered/unordered_node_set.hpp>
|
|
//
|
|
// Note: no multiset version
|
|
|
|
namespace boost {
|
|
template <
|
|
class Key,
|
|
class Hash = boost::hash<Key>,
|
|
class Pred = std::equal_to<Key>,
|
|
class Alloc = std::allocator<Key> >
|
|
class unordered_node_set;
|
|
}
|
|
----
|
|
|
|
[source,c++]
|
|
----
|
|
// #include <boost/unordered/unordered_node_map.hpp>
|
|
//
|
|
// Note: no multimap version
|
|
|
|
namespace boost {
|
|
template <
|
|
class Key, class Mapped,
|
|
class Hash = boost::hash<Key>,
|
|
class Pred = std::equal_to<Key>,
|
|
class Alloc = std::allocator<std::pair<Key const, Mapped> > >
|
|
class unordered_node_map;
|
|
}
|
|
----
|
|
|
|
These are all the containers provided by Boost.Unordered:
|
|
|
|
[caption=, title='Table {counter:table-counter}. Boost.Unordered containers']
|
|
[cols="1,1,.^1", frame=all, grid=rows]
|
|
|===
|
|
^h|
|
|
^h|*Node-based*
|
|
^h|*Flat*
|
|
|
|
^.^h|*Closed addressing*
|
|
^| `boost::unordered_set` +
|
|
`boost::unordered_map` +
|
|
`boost::unordered_multiset` +
|
|
`boost::unordered_multimap`
|
|
^|
|
|
|
|
^.^h|*Open addressing*
|
|
^| `boost::unordered_node_set` +
|
|
`boost::unordered_node_map`
|
|
^| `boost::unordered_flat_set` +
|
|
`boost::unordered_flat_map`
|
|
|
|
|===
|
|
|
|
Closed-addressing containers are pass:[C++]98-compatible. Open-addressing containers require a
|
|
reasonably compliant pass:[C++]11 compiler.
|
|
|
|
Boost.Unordered containers are used in a similar manner to the normal associative
|
|
containers:
|
|
|
|
[source,cpp]
|
|
----
|
|
typedef boost::unordered_map<std::string, int> map;
|
|
map x;
|
|
x["one"] = 1;
|
|
x["two"] = 2;
|
|
x["three"] = 3;
|
|
|
|
assert(x.at("one") == 1);
|
|
assert(x.find("missing") == x.end());
|
|
----
|
|
|
|
But since the elements aren't ordered, the output of:
|
|
|
|
[source,c++]
|
|
----
|
|
for(const map::value_type& i: x) {
|
|
std::cout<<i.first<<","<<i.second<<"\n";
|
|
}
|
|
----
|
|
|
|
can be in any order. For example, it might be:
|
|
|
|
[source]
|
|
----
|
|
two,2
|
|
one,1
|
|
three,3
|
|
----
|
|
|
|
To store an object in an unordered associative container requires both a
|
|
key equality function and a hash function. The default function objects in
|
|
the standard containers support a few basic types including integer types,
|
|
floating point types, pointer types, and the standard strings. Since
|
|
Boost.Unordered uses link:../../../container_hash/index.html[boost::hash^] it also supports some other types,
|
|
including standard containers. To use any types not supported by these methods
|
|
you have to extend Boost.Hash to support the type or use
|
|
your own custom equality predicates and hash functions. See the
|
|
<<hash_equality,Equality Predicates and Hash Functions>> section
|
|
for more details.
|
|
|
|
There are other differences, which are listed in the
|
|
<<comparison,Comparison with Associative Containers>> section.
|