mirror of
https://github.com/boostorg/container.git
synced 2026-07-05 10:30:47 +02:00
Expanded flat_set/map section
This commit is contained in:
+40
-2
@@ -413,8 +413,8 @@ its erase functions (AssocVector::erase invalidates all iterators into the objec
|
||||
complexity guarantees of insert and erase (linear as opposed to constant). ]]
|
||||
|
||||
[*Boost.Container] [classref boost::container::flat_map flat_map], [classref boost::container::flat_set flat_set], [classref boost::container::flat_multimap flat_multimap] and [classref boost::container::flat_multiset flat_multiset] containers are ordered, vector-like container based, associative
|
||||
containers following Austern's and Alexandrescu's guidelines. These ordered vector containers have also
|
||||
benefited with the addition of `move semantics` to C++11, speeding up insertion and
|
||||
containers following Austern's and Alexandrescu's guidelines. These ordered vector-like containers have also
|
||||
benefited with the addition of `move semantics`, speeding up insertion and
|
||||
erasure times considerably. Flat associative containers have the following attributes:
|
||||
|
||||
* Faster lookup than standard associative containers
|
||||
@@ -428,6 +428,44 @@ erasure times considerably. Flat associative containers have the following attri
|
||||
(copy/move constructors can throw when shifting values in erasures and insertions)
|
||||
* Slower insertion and erasure than standard associative containers (specially for non-movable types)
|
||||
|
||||
[*Differences with the standard `std::flat_map`/`std::flat_set`]. C++23 added `std::flat_map`, `std::flat_set`,
|
||||
`std::flat_multimap` and `std::flat_multiset`, based on the same sorted-vector idea. There are, however, several
|
||||
notable differences with [*Boost.Container]'s long-standing implementation (available since 2004 and usable from
|
||||
C++03 onwards):
|
||||
|
||||
* [*Container vs. container adaptor]: [*Boost.Container]'s flat containers are full-fledged containers that own a
|
||||
single underlying sorted sequence. The standard ones are container [*adaptors] layered on top of user-provided
|
||||
sequence containers, exposed through `keys()`/`values()` accessors and `extract()`/`replace()` operations.
|
||||
|
||||
* [*Storage layout for maps] (array of structs vs. structure of arrays):
|
||||
[classref boost::container::flat_map flat_map] stores its elements as a single sequence of `value_type` =
|
||||
`std::pair<Key, T>`, so each key is interleaved with its mapped value in one contiguous buffer. `std::flat_map`
|
||||
instead keeps keys and mapped values in two [*separate] parallel containers (`key_container_type` and
|
||||
`mapped_container_type`). The standard layout can speed up key-only scans (lookups touch only the keys array) at
|
||||
the cost of an extra indirection when both key and value are needed, while Boost's layout keeps each key next to
|
||||
its value.
|
||||
|
||||
* [*Iterators and `value_type`]: because [classref boost::container::flat_map flat_map] holds real
|
||||
`std::pair<Key, T>` objects, its iterators dereference to actual pair lvalues and `&*it` yields a pointer to a
|
||||
stored pair. `std::flat_map`, having two arrays, exposes proxy references of type
|
||||
`pair<const key_type&, mapped_type&>` and does not provide pointers into a single pair array.
|
||||
|
||||
* [*Underlying sequence access]: [*Boost.Container] exposes the whole sorted vector through `sequence_type`,
|
||||
`extract_sequence()` and `adopt_sequence()` (optionally with the `ordered_unique_range_t` tag for an O(1)
|
||||
adoption), which is handy to build the container cheaply and then re-adopt it. The standard counterpart uses
|
||||
`extract()`/`replace()` returning the key and mapped containers separately.
|
||||
|
||||
* [*Availability and configurability]: [*Boost.Container]'s flat containers work from C++03, let you choose the
|
||||
underlying vector-like sequence (e.g. [classref boost::container::small_vector small_vector] or
|
||||
[classref boost::container::static_vector static_vector]) through a template parameter and offer additional
|
||||
ordered-range insertion overloads.
|
||||
|
||||
The following example shows the most common operations, the single-sequence storage and the
|
||||
`extract_sequence`/`adopt_sequence` idiom:
|
||||
|
||||
[import ../example/doc_flat_map.cpp]
|
||||
[doc_flat_map]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:devector ['devector]]
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2024-2024. 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)
|
||||
//
|
||||
// See http://www.boost.org/libs/container for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//[doc_flat_map
|
||||
#include <boost/container/flat_map.hpp>
|
||||
#include <boost/move/utility_core.hpp> //boost::move
|
||||
|
||||
//Make sure assertions are active
|
||||
#ifdef NDEBUG
|
||||
#undef NDEBUG
|
||||
#endif
|
||||
#include <cassert>
|
||||
|
||||
int main ()
|
||||
{
|
||||
using namespace boost::container;
|
||||
|
||||
typedef flat_map<int, int> map_t;
|
||||
|
||||
map_t m;
|
||||
|
||||
//Like vector, we can reserve storage to avoid reallocations while filling.
|
||||
m.reserve(8);
|
||||
|
||||
//Insertions keep the underlying vector sorted by key. They are O(N)
|
||||
//because the elements after the insertion point must be shifted.
|
||||
m[30] = 3;
|
||||
m[10] = 1;
|
||||
m[20] = 2;
|
||||
assert(m.size() == 3);
|
||||
|
||||
//Iteration is in key order and over contiguous memory, using random-access
|
||||
//iterators, so it is much faster than a node-based std::map.
|
||||
{
|
||||
map_t::const_iterator it = m.begin();
|
||||
assert(it->first == 10 && it->second == 1); ++it;
|
||||
assert(it->first == 20 && it->second == 2); ++it;
|
||||
assert(it->first == 30 && it->second == 3);
|
||||
}
|
||||
|
||||
//Lookup uses binary search: O(log N).
|
||||
map_t::iterator f = m.find(20);
|
||||
assert(f != m.end() && f->second == 2);
|
||||
|
||||
//All values live in a single underlying sequence of value_type, which is
|
||||
//std::pair<Key, T> (an array of structs). This is a key difference with the
|
||||
//C++23 std::flat_map, a container *adaptor* that keeps keys and mapped
|
||||
//values in two separate, parallel containers (a structure of arrays).
|
||||
const map_t::value_type *raw = &*m.begin();
|
||||
assert(raw[0].first == 10 && raw[2].first == 30);
|
||||
|
||||
//The underlying sorted vector can be moved out with extract_sequence() and
|
||||
//moved back in with adopt_sequence(). Because the extracted sequence is
|
||||
//already ordered and free of duplicates, we can re-adopt it in O(1) using
|
||||
//the ordered_unique_range_t overload.
|
||||
map_t::sequence_type seq = m.extract_sequence();
|
||||
assert(m.empty());
|
||||
m.adopt_sequence(ordered_unique_range_t(), boost::move(seq));
|
||||
assert(m.size() == 3 && m.find(30) != m.end());
|
||||
|
||||
return 0;
|
||||
}
|
||||
//]
|
||||
Reference in New Issue
Block a user