# Boost.MultiIndex Index reference

`multi_index_container` reference
Boost.MultiIndex reference
Ordered indices

## Contents

- Index concepts
- Complexity signature
- Index specification
- Header `"boost/multi_index/indexed_by.hpp"` synopsis
  - Class template `indexed_by`
- Tags
- Header `"boost/multi_index/tag.hpp"` synopsis
  - Class template `tag`
- Indices provided by Boost.MultiIndex
  - Key-based indices
  - Other types
- Index views

## Index concepts

`multi_index_container` instantiations comprise one or more indices specified at compile time. Each index allows read/write access to the elements contained in a definite manner. For instance, ordered indices provide a set-like interface to the elements, whereas sequenced indices mimic the functionality of `std::list`.

Indices are not isolated objects, and so cannot be constructed on their own. Rather they are embedded into a `multi_index_container` as specified by means of an index specifier. The name of the index class implementation proper is never directly exposed to the user, who has only access to the associated index specifier.

Insertion and erasing of elements are always performed through the appropriate interface of some index of the `multi_index_container`; these operations, however, do have an impact on all other indices as well: for instance, insertion through a given index may fail because there exists another index which bans the operation in order to preserve its invariant (like uniqueness of elements.) This circumstance, rather than being an obstacle, yields much of the power of Boost.MultiIndex: equivalent constructions based on manual composition of standard containers would have to add a fair amount of code in order to globally preserve the invariants of each container while guaranteeing that all of them are synchronized. The global operations performed in a joint manner among the various indices can be reduced to six primitives:

- Copying,
- insertion of an element,
- hinted insertion, where a preexisting element is suggested in order to improve the efficiency of the operation,
- deletion of an element,
- replacement of the value of an element, which may trigger the rearrangement of this element in one or more indices, or the banning of the replacement,
- modification of an element, and its subsequent rearrangement/banning by the various indices.

The last two primitives deserve some further explanation: in order to guarantee the invariants associated to each index (e.g. some definite ordering,) elements of a `multi_index_container` are not mutable. To overcome this restriction, indices expose member functions for replacement and modification which allow for the mutation of elements in a controlled fashion. Immutability of elements does not significantly impact the interfaces of ordered and hashed indices, as they are based upon those of associative and unordered associative containers, respectively, and these containers also have non-mutable elements; but it may come as a surprise when dealing with sequenced and random access indices, which are designed upon the functionality provided by `std::list`.

These global operations are not directly exposed to the user, but rather they are wrapped as appropriate by each index (for instance, ordered indices provide a set-like suite of insertion member functions, whereas sequenced and random access indices have `push_back` and `push_front` operations.) Boost.MultiIndex poses no particular conditions on the interface of indices, although each index provided satisfy the C++ requirements for standard containers to the maximum extent possible within the conceptual framework of the library.

## Complexity signature

Some member functions of an index interface are implemented by global primitives from the list above. Complexity of these operations thus depends on all indices of a given `multi_index_container`, not just the currently used index.

In order to establish complexity estimates, an index is characterized by its complexity signature, consisting of the following associated functions on the number of elements:

- `c(n)`: copying,
- `i(n)`: insertion,
- `h(n)`: hinted insertion,
- `d(n)`: deletion,
- `r(n)`: replacement,
- `m(n)`: modifying.

Each function yields the complexity estimate of the contribution of the index to the corresponding global primitive. Let us consider an instantiation of `multi_index_container` with `N` indices labelled `0`,...,`N-1` whose complexity signatures are (`ci`,`ii`,`hi`,`di`,`ri`,`mi`); the insertion of an element in such a container is then of complexity `O(i0(n)+···+iN-1(n))` where `n` is the number of elements. To abbreviate notation, we adopt the following definitions:

- `C(n)=c0(n)+···+cN-1(n)`,
- `I(n)=i0(n)+···+iN-1(n)`,
- `H(n)=h0(n)+···+hN-1(n)`,
- `D(n)=d0(n)+···+dN-1(n)`,
- `R(n)=r0(n)+···+rN-1(n)`,
- `M(n)=m0(n)+···+mN-1(n)`.

For instance, consider a `multi_index_container` with two ordered indices, for which `i(n)=log(n)`, and a sequenced index with `i(n)=1` (constant time insertion). Insertion of an element into this `multi_index_container` is then of complexity

> `O(I(n))=O(2*log(n)+1)=O(log(n))`.

## Index specification

Index specifiers are passed as instantiation arguments to `multi_index_container` and provide the information needed to incorporate the corresponding indices. Future releases of Boost.MultiIndex may allow for specification of user-defined indices. Meanwhile, the requirements for an index specifier remain implementation defined. Currently, Boost.MultiIndex provides the index specifiers

- `ordered_unique` and `ordered_non_unique` for ordered indices,
- `ranked_unique` and `ranked_non_unique` for ranked indices,
- `hashed_unique` and `hashed_non_unique` for hashed indices,
- `sequenced` for sequenced indices,
- and `random_access` for random access indices.

## Header `"boost/multi_index/indexed_by.hpp"` synopsis

>     namespace boost{

>     namespace multi_index{

>     template<typename T0,...,typename Tn>
>     struct indexed_by;

>     } // namespace boost::multi_index

>     } // namespace boost

### Class template `indexed_by`

`indexed_by` is a model of `MPL Random Access Sequence` and `MPL Extensible Sequence` meant to be used to specify a compile-time list of indices as the `IndexSpecifierList` of `multi_index_container`.

>     template<typename T0,...,typename Tn>
>     struct indexed_by;

Each user-provided element of `indexed_list` must be an index specifier. At least an element must be provided. The maximum number of elements of an `indexed_by` sequence is implementation defined.

## Tags

Tags are just conventional types used as mnemonics for indices of an `multi_index_container`, as for instance in member function `get`. Each index can have none, one or more tags associated. The way tags are assigned to a given index is dependent on the particular index specifier. However, for convenience all indices of Boost.MultiIndex support tagging through the class template `tag`.

## Header `"boost/multi_index/tag.hpp"` synopsis

>     namespace boost{

>     namespace multi_index{

>     template<typename T0,...,typename Tn>
>     struct tag;

>     } // namespace boost::multi_index

>     } // namespace boost

### Class template `tag`

`tag` is a typelist construct used to specify a compile-time sequence of tags to be assigned to an index in instantiation time.

>     template<typename T0,...,typename Tn>
>     struct tag
>     {
>       typedef implementation defined type;
>     };

Elements of `tag` can be any type, though the user is expected to provide classes with mnemonic names. Duplicate elements are not allowed. The maximum number of elements of a `tag` instantiation is implementation defined. The nested `type` is a model of `MPL Random Access Sequence` and `MPL Extensible Sequence` containing the types `T0`, ... , `Tn` in the same order as specified.

## Indices provided by Boost.MultiIndex

### Key-based indices

Indices of this type are organized around keys obtained from the elements, as described in the key extraction reference.

- Ordered indices sort the elements on the key and provide fast lookup capabilites.
- Ranked indices are a variation of ordered indices providing extra operations based on rank, the numerical position of an element in the sequence.
- Hashed indices offer high efficiency access through hashing techniques.

### Other types

- Sequenced indices allow to arrange elements as in a bidirectional list.
- Random access indices provide constant time positional access and free ordering of elements.

## Index views

The following concept is used by the rearrange facilities of non key-based indices. Given an index `i` of type `Index`, a view of `i` is any range [`first`,`last`) where `first` and `last` are input iterators such that

1. the associated value type of `Iterator` is convertible to `const Index::value_type&`
2. and each of the elements of `i` appears exactly once in [`first`,`last`).

Note that the view refers to the actual elements of `i`, not to copies of them. Additionally, a view is said to be free if its traversal order is not affected by changes in the traversal order of `i`. Examples of free views are:

- [`c.begin()`,`c.end()`), where `c` is any container of reference wrappers (from Boost.Ref) to the elements of `i` containing exactly one reference to every element.
- [`i'.begin()`,`i'.end()`), where `i'` is any index belonging to the same `multi_index_container` as `i`, except `i` itself.
- Any range which is a permutation of the ones described above, as for instance [`c.rbegin()`,`c.rend()`), or ranges obtained from the former with the aid of `permutation_iterator` from Boost.Iterator.

`multi_index_container` reference
Boost.MultiIndex reference
Ordered indices

Revised January 9th 2020

© Copyright 2003-2020 Joaquín M López Muñoz. 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)