[DEV] add v1.66.0

This commit is contained in:
2018-01-12 21:47:58 +01:00
parent 87059bb1af
commit a97e9ae7d4
49032 changed files with 7668950 additions and 0 deletions

View File

@@ -0,0 +1,205 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0.1 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Boost.MultiIndex Documentation - Acknowledgements</title>
<link rel="stylesheet" href="style.css" type="text/css">
<link rel="start" href="index.html">
<link rel="prev" href="release_notes.html">
<link rel="up" href="index.html">
</head>
<body>
<h1><img src="../../../boost.png" alt="boost.png (6897 bytes)" align=
"middle" width="277" height="86">Boost.MultiIndex Acknowledgements</h1>
<div class="prev_link"><a href="release_notes.html"><img src="prev.gif" alt="release notes" border="0"><br>
Release notes
</a></div>
<div class="up_link"><a href="index.html"><img src="up.gif" alt="index" border="0"><br>
Index
</a></div>
<div class="next_link">
</div><br clear="all" style="clear: all;">
<hr>
<p>
Fernando Cacciola, Darren Cook, Beman Dawes, Jeremy Maitin-Shepard and Daryle
Walker from the Boost mailing list provided useful suggestions for improvement
on the first alpha releases of the library. Gang Wang discovered several
bugs in the code. Thomas Wenisch brought out the idea of "sequence sets"
from which sequenced indices were designed. Giovanni Bajo, Chris Little and
Maxim Yegorushkin tested the library on several platforms. Daniel Wallin
contributed fixes for MSVC++ 7.0. Ron Liechty and the support staff at
Metrowerks provided assistance during the porting of the library to CW 8.3.
Porting to VisualAge 6.0 counted on Toon Knapen's help. Markus Sch&ouml;pflin
aided with Compaq C++ 6.5 and GCC for Tru64 UNIX. Rosa Bern&aacute;rdez proofread the
last versions of the tutorial.
</p>
<p>
Pavel Vo&#382;en&iacute;lek has been immensely helpful in thoroughly reviewing
every single bit of the library, and he also suggested several extra
functionalities, most notably range querying, safe mode, polymorphic key
extractors and MPL support. Thank you!
</p>
<p>
The Boost acceptance review took place between March 20th and 30th 2004.
Pavel Vo&#382;en&iacute;lek was the review manager. Thanks to all the people
who participated and specially to those who submitted reviews:
Fredrik Blomqvist, Tom Brinkman, Paul A Bristow, Darren Cook, Jeff Garland,
David B. Held, Brian McNamara, Gary Powell, Rob Stewart, Arkadiy Vertleyb,
J&ouml;rg Walter. Other Boost members also contributed ideas, particularly
in connection with the library's naming scheme: Pavol Droba,
Dave Gomboc, Jeremy Maitin-Shepard, Thorsten Ottosen, Matthew Vogt,
Daryle Walker. My apologies if I inadvertently left somebody out of this
list.
</p>
<p>
Boost.MultiIndex could not have been written without Aleksey Gurtovoy
et al. superb <a href="../../../libs/mpl/doc/index.html">Boost MPL
Library</a>. Also, Aleksey's techniques for dealing with ETI-related
problems in MSVC++ 6.0 helped solve some internal issues of the library.
</p>
<p>
The internal implementation of red-black trees is based on that of SGI STL
<a href="http://www.sgi.com/tech/stl/stl_tree.h">stl_tree.h</a> file:
</p>
<blockquote>
Copyright (c) 1996,1997
Silicon Graphics Computer Systems, Inc.
<br>
Permission to use, copy, modify, distribute and sell this software
and its documentation for any purpose is hereby granted without fee,
provided that the above copyright notice appear in all copies and
that both that copyright notice and this permission notice appear
in supporting documentation. Silicon Graphics makes no
representations about the suitability of this software for any
purpose. It is provided &quot;as is&quot; without express or implied warranty.
<br>
<br>
Copyright (c) 1994
Hewlett-Packard Company
<br>
Permission to use, copy, modify, distribute and sell this software
and its documentation for any purpose is hereby granted without fee,
provided that the above copyright notice appear in all copies and
that both that copyright notice and this permission notice appear
in supporting documentation. Hewlett-Packard Company makes no
representations about the suitability of this software for any
purpose. It is provided &quot;as is&quot; without express or implied warranty.
</blockquote>
<p>
<span style="float:right;margin-left:10px"><img src="lopez.jpg" width="160" height="120"></span>
I would like to dedicate this piece of work to Rosa Bern&aacute;rdez, my very first
C++ teacher, for her unconditional support in many endeavors of which programming is
by no means the most important. In memory of my cat L&oacute;pez (2001-2003): he
lived too fast, died too young.
<br style="clear:all;">
</p>
<h2><a name="boost_1_33">Boost 1.33 release</a></h2>
<p>
Many thanks again to Pavel Vo&#382;en&iacute;lek, who has carefully reviewed
the new material and suggested many improvements. The design of hashed indices
has benefited from discussions with several Boost members, most notably
Howard Hinnant and Daniel James. Daniel has also contributed
<a href="../../functional/hash/index.html">Boost.Hash</a>
to the community: hashed indices depend on this library as
their default hash function provider. Robert Ramey's
<a href="../../serialization/index.html">Boost Serialization Library</a>
provides the very solid framework upon which Boost.MultiIndex serialization
capabilities are built. Toon Knapen helped adjust the library for VisualAge 6.0.
Markus Sch&ouml;pflin provided a Jamfile tweak for GCC under Tru64 UNIX.
</p>
<h2><a name="boost_1_34">Boost 1.34 release</a></h2>
<p>
<span style="float:left;margin-right:10px"><img src="hector.jpg" width="150" height="198"></span>
Thanks go to Pavel Vo&#382;en&iacute;lek for his useful comments and suggestions
during the development of this release, and to Rosa Bern&aacute;rdez for reviewing
the new material in the documentation.
Alo Sarv suggested a notational improvement in the specification of
partial searches with composite keys.
Maxim Yegorushkin proposed a valuable
<a href="tutorial/indices.html#ordered_node_compression">spatial optimization</a>
for ordered indices and provided figures of its impact on performance
for containers with large numbers of elements.
Caleb Epstein performed the tests under MSVC++ 8.0 described in the
performance section. The following people have reported bugs and problems with
previous versions and prereleases of the library: Alexei Alexandrov,
Mat&iacute;as Capeletto, John Eddy, Martin Eigel, Guillaume Lazzara,
Felipe Magno de Almeida, Julien Pervill&eacute;, Hubert Schmid, Toby Smith.
</p>
<p>
New member in the family! Thanks to H&eacute;ctor for his patience during
long development sessions and his occasional contributions to the source
codebase.
<br style="clear:all;">
</p>
<h2><a name="boost_1_35">Boost 1.35 release</a></h2>
<p>
<a href="tutorial/key_extraction.html#global_fun"><code>global_fun</code></a>
was included after a proposal by Markus Werle. Bruno Mart&iacute;nez Aguerre
suggested the inclusion of
<a href="tutorial/indices.html#iterator_to"><code>iterator_to</code></a>. The
rollback versions of <code>modify</code> and <code>modify_key</code> arose
from discussions with Mat&iacute;as Capeletto. Steven Watanabe spotted an
include guard bug present from the first release of the library.
</p>
<h2><a name="boost_1_36">Boost 1.36 release</a></h2>
<p>
Thanks to Amit Jain for reporting a problem with allocator management.
Michael Fawcett proposed the addition of an allocator constructor to
<code>multi_index_container</code>.
A report from Zachary Zhou has led to
<a href="release_notes.html#stable_update">enhancing the behavior of
hashed indices update functions</a> so that they meet some intuitive expectations.
Grzegorz Jakacki spotted some internal dead code.
</p>
<h2><a name="boost_1_56">Boost 1.56 release</a></h2>
<p>
Stephen Kelly has contributed the removal of workaround code for old compilers
no longer supported.
</p>
<hr>
<div class="prev_link"><a href="release_notes.html"><img src="prev.gif" alt="release notes" border="0"><br>
Release notes
</a></div>
<div class="up_link"><a href="index.html"><img src="up.gif" alt="index" border="0"><br>
Index
</a></div>
<div class="next_link">
</div><br clear="all" style="clear: all;">
<br>
<p>Revised October 9th 2013</p>
<p>&copy; Copyright 2003-2013 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz.
Distributed under the Boost Software
License, Version 1.0. (See accompanying file <a href="../../../LICENSE_1_0.txt">
LICENSE_1_0.txt</a> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">
http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</body>
</html>

View File

@@ -0,0 +1,390 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0.1 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Boost.MultiIndex Documentation - Compiler specifics</title>
<link rel="stylesheet" href="style.css" type="text/css">
<link rel="start" href="index.html">
<link rel="prev" href="reference/key_extraction.html">
<link rel="up" href="index.html">
<link rel="next" href="performance.html">
</head>
<body>
<h1><img src="../../../boost.png" alt="boost.png (6897 bytes)" align=
"middle" width="277" height="86">Boost.MultiIndex Compiler specifics</h1>
<div class="prev_link"><a href="reference/key_extraction.html"><img src="prev.gif" alt="key extraction" border="0"><br>
Key extraction
</a></div>
<div class="up_link"><a href="index.html"><img src="up.gif" alt="index" border="0"><br>
Index
</a></div>
<div class="next_link"><a href="performance.html"><img src="next.gif" alt="performance" border="0"><br>
Performance
</a></div><br clear="all" style="clear: all;">
<hr>
<p>
Boost.MultiIndex utilizes some C++11 capabilities but is also equipped
to work reasonably well in decent C++03-compliant environments.
We list some of the possible limitations along with suitable workarounds when available.
</p>
<h2>Contents</h2>
<ul>
<li><a href="#move">Move semantics</a></li>
<li><a href="#emplace">Emplace functions</a></li>
<li><a href="#initializer_list">Initializer lists</a></li>
<li><a href="#tuple">Tuples</a></li>
<li><a href="#symbol_reduction">Reduction of symbol name lengths</a>
<ul>
<li><a href="#argument_limitation">Limitation of maximum number of arguments</a></li>
<li><a href="#type_hiding">Type hiding</a></li>
</ul>
</li>
<li><a href="#legacy">Legacy compilers</a></li>
</ul>
<h2><a name="move">Move semantics</a></h2>
<p>
Boost.MultiIndex uses <a href="../../../doc/html/move.html">Boost.Move</a>
to support compilers without rvalue references. In such scenarios, taking
advantage of <code>multi_index_container&lt;Value&gt;</code> capabilities for
increased efficiency in insertion and handling of moveable-only elements will
require that <code>Value</code> be suitably instrumented.
</p>
<h2><a name="emplace">Emplace functions</a></h2>
<p>
In compilers without variadic template support, Boost.MultiIndex emplace
functions emulate this missing functionality by accepting up to
<code>BOOST_MULTI_INDEX_LIMIT_VARTEMPL_ARGS</code>
construction arguments that are internally forwarded with
<a href="../../../doc/html/move.html">Boost.Move</a>:
only constant lvalue references and rvalues are permitted as construction arguments
in such case.
</p>
<p>
<code>BOOST_MULTI_INDEX_LIMIT_VARTEMPL_ARGS</code>, which by default is 5, can
be globally defined by the user to a different value.
</p>
<h2><a name="initializer_list">Initializer lists</a></h2>
<p>
No transparent emulation of this functionality can be provided in the absence of
<code>std::initializer_list</code>: consider
<a href="../../../libs/assign/index.html">Boost.Assign</a> as a
possible replacement.
</p>
<h2><a name="tuple">Tuples</a></h2>
<p>
Everywhere where <code>std::tuple</code>s are used in the library interface,
<code>boost::tuple</code>s can be resorted to in their place. The converse, however,
is not true.
</p>
<h2><a name="symbol_reduction">Reduction of symbol name lengths</a></h2>
<p>
The types generated on the instantiations of <code>multi_index_container</code>s
typically produce very long symbol names, sometimes beyond the internal limits
of some compilers. There are several techniques to shorten generated symbol
names: these techniques have also the beneficial side effect that resulting error
messages are more readable.
</p>
<h3><a name="argument_limitation">Limitation of maximum number of arguments</a></h3>
<p>
The class templates <a href="reference/indices.html#indexed_by"><code>indexed_by</code></a>,
<a href="reference/indices.html#tag"><code>tag</code></a> and
<a href="reference/key_extraction.html#composite_key"><code>composite_key</code></a>
accept a variable number of arguments whose maximum number is limited by
internal macros. Even non-used arguments contribute to the final types,
so manually adjusting the corresponding macros can result in a modest reduction
of symbol names.
</p>
<p align="center">
<table cellspacing="0">
<caption><b>Limiting maximum number of arguments of some class templates
of Boost.MultiIndex.</b></caption>
<tr>
<th>class template</th>
<th>limiting macro</th>
<th>default value</th>
</tr>
<tr>
<td align="center">&nbsp;<code>indexed_by</code>&nbsp;</td>
<td align="center">&nbsp;<code>BOOST_MULTI_INDEX_LIMIT_INDEXED_BY_SIZE</code>&nbsp;</td>
<td align="center">20</td>
</tr>
<tr class="odd_tr">
<td align="center">&nbsp;<code>tag</code>&nbsp;</td>
<td align="center">&nbsp;<code>BOOST_MULTI_INDEX_LIMIT_TAG_SIZE</code>&nbsp;</td>
<td align="center">20</td>
</tr>
<tr>
<td align="center">&nbsp;<code>composite_key</code>&nbsp;</td>
<td align="center">&nbsp;<code>BOOST_MULTI_INDEX_LIMIT_COMPOSITE_KEY_SIZE</code>&nbsp;</td>
<td align="center">10</td>
</tr>
</table>
</p>
<h3><a name="type_hiding">Type hiding</a></h3>
<p>
Consider a typical instantiation of <code>multi_index_container</code>:
</p>
<blockquote><pre>
<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special>&lt;</span>
<span class=identifier>employee</span><span class=special>,</span>
<span class=identifier>indexed_by</span><span class=special>&lt;</span>
<span class=identifier>ordered_unique</span><span class=special>&lt;</span><span class=identifier>identity</span><span class=special>&lt;</span><span class=identifier>employee</span><span class=special>&gt;</span> <span class=special>&gt;,</span>
<span class=identifier>ordered_non_unique</span><span class=special>&lt;</span><span class=identifier>member</span><span class=special>&lt;</span><span class=identifier>employee</span><span class=special>,</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>,&amp;</span><span class=identifier>employee</span><span class=special>::</span><span class=identifier>name</span><span class=special>&gt;</span> <span class=special>&gt;,</span>
<span class=identifier>ordered_unique</span><span class=special>&lt;</span><span class=identifier>member</span><span class=special>&lt;</span><span class=identifier>employee</span><span class=special>,</span><span class=keyword>int</span><span class=special>,&amp;</span><span class=identifier>employee</span><span class=special>::</span><span class=identifier>ssnumber</span><span class=special>&gt;</span> <span class=special>&gt;</span>
<span class=special>&gt;</span>
<span class=special>&gt;</span> <span class=identifier>employee_set</span><span class=special>;</span>
</pre></blockquote>
<p>
Then, for instance, the type <code>employee_set::nth_index&lt;0&gt;::type</code>
resolves to the following in GCC:
</p>
<blockquote><pre>
<span class=identifier>boost</span><span class=special>::</span><span class=identifier>multi_index</span><span class=special>::</span><span class=identifier>detail</span><span class=special>::</span><span class=identifier>ordered_index</span><span class=special>&lt;</span>
<span class=identifier>boost</span><span class=special>::</span><span class=identifier>multi_index</span><span class=special>::</span><span class=identifier>identity</span><span class=special>&lt;</span><span class=identifier>employee</span><span class=special>&gt;,</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>less</span><span class=special>&lt;</span><span class=identifier>employee</span><span class=special>&gt;,</span>
<span class=identifier>boost</span><span class=special>::</span><span class=identifier>multi_index</span><span class=special>::</span><span class=identifier>detail</span><span class=special>::</span><span class=identifier>nth_layer</span><span class=special>&lt;</span>
<span class=number>1</span><span class=special>,</span> <span class=identifier>employee</span><span class=special>,</span>
<span class=identifier>boost</span><span class=special>::</span><span class=identifier>multi_index</span><span class=special>::</span><span class=identifier>indexed_by</span><span class=special>&lt;</span>
<span class=identifier>boost</span><span class=special>::</span><span class=identifier>multi_index</span><span class=special>::</span><span class=identifier>ordered_unique</span><span class=special>&lt;</span>
<span class=identifier>boost</span><span class=special>::</span><span class=identifier>multi_index</span><span class=special>::</span><span class=identifier>identity</span><span class=special>&lt;</span><span class=identifier>employee</span><span class=special>&gt;,</span> <span class=identifier>mpl_</span><span class=special>::</span><span class=identifier>na</span><span class=special>,</span> <span class=identifier>mpl_</span><span class=special>::</span><span class=identifier>na</span>
<span class=special>&gt;,</span>
<span class=identifier>boost</span><span class=special>::</span><span class=identifier>multi_index</span><span class=special>::</span><span class=identifier>ordered_non_unique</span><span class=special>&lt;</span>
<span class=identifier>boost</span><span class=special>::</span><span class=identifier>multi_index</span><span class=special>::</span><span class=identifier>member</span><span class=special>&lt;</span><span class=identifier>employee</span><span class=special>,</span> <span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>,</span> <span class=special>&amp;</span><span class=identifier>employee</span><span class=special>::</span><span class=identifier>name</span><span class=special>&gt;,</span>
<span class=identifier>mpl_</span><span class=special>::</span><span class=identifier>na</span><span class=special>,</span> <span class=identifier>mpl_</span><span class=special>::</span><span class=identifier>na</span>
<span class=special>&gt;,</span>
<span class=identifier>boost</span><span class=special>::</span><span class=identifier>multi_index</span><span class=special>::</span><span class=identifier>ordered_unique</span><span class=special>&lt;</span>
<span class=identifier>boost</span><span class=special>::</span><span class=identifier>multi_index</span><span class=special>::</span><span class=identifier>member</span><span class=special>&lt;</span><span class=identifier>employee</span><span class=special>,</span> <span class=keyword>int</span><span class=special>,</span> <span class=special>&amp;</span><span class=identifier>employee</span><span class=special>::</span><span class=identifier>ssnumber</span><span class=special>&gt;,</span>
<span class=identifier>mpl_</span><span class=special>::</span><span class=identifier>na</span><span class=special>,</span> <span class=identifier>mpl_</span><span class=special>::</span><span class=identifier>na</span>
<span class=special>&gt;,</span>
<span class=identifier>mpl_</span><span class=special>::</span><span class=identifier>na</span><span class=special>,</span> <span class=identifier>mpl_</span><span class=special>::</span><span class=identifier>na</span><span class=special>,</span> <span class=identifier>mpl_</span><span class=special>::</span><span class=identifier>na</span><span class=special>,</span> <span class=identifier>mpl_</span><span class=special>::</span><span class=identifier>na</span><span class=special>,</span> <span class=identifier>mpl_</span><span class=special>::</span><span class=identifier>na</span><span class=special>,</span> <span class=identifier>mpl_</span><span class=special>::</span><span class=identifier>na</span><span class=special>,</span>
<span class=identifier>mpl_</span><span class=special>::</span><span class=identifier>na</span><span class=special>,</span> <span class=identifier>mpl_</span><span class=special>::</span><span class=identifier>na</span><span class=special>,</span> <span class=identifier>mpl_</span><span class=special>::</span><span class=identifier>na</span><span class=special>,</span> <span class=identifier>mpl_</span><span class=special>::</span><span class=identifier>na</span><span class=special>,</span> <span class=identifier>mpl_</span><span class=special>::</span><span class=identifier>na</span><span class=special>,</span> <span class=identifier>mpl_</span><span class=special>::</span><span class=identifier>na</span><span class=special>,</span>
<span class=identifier>mpl_</span><span class=special>::</span><span class=identifier>na</span><span class=special>,</span> <span class=identifier>mpl_</span><span class=special>::</span><span class=identifier>na</span><span class=special>,</span> <span class=identifier>mpl_</span><span class=special>::</span><span class=identifier>na</span><span class=special>,</span> <span class=identifier>mpl_</span><span class=special>::</span><span class=identifier>na</span><span class=special>,</span> <span class=identifier>mpl_</span><span class=special>::</span><span class=identifier>na</span>
<span class=special>&gt;,</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>allocator</span><span class=special>&lt;</span><span class=identifier>employee</span><span class=special>&gt;</span>
<span class=special>&gt;,</span>
<span class=identifier>boost</span><span class=special>::</span><span class=identifier>mpl</span><span class=special>::</span><span class=identifier>vector0</span><span class=special>&lt;</span><span class=identifier>mpl_</span><span class=special>::</span><span class=identifier>na</span><span class=special>&gt;,</span>
<span class=identifier>boost</span><span class=special>::</span><span class=identifier>multi_index</span><span class=special>::</span><span class=identifier>detail</span><span class=special>::</span><span class=identifier>ordered_unique_tag</span>
<span class=special>&gt;</span>
</pre></blockquote>
<p>
It can be seen that a significant portion of the type name is contributed by
the <code>indexed_by&lt;...&gt;</code> part, which is nothing but an expanded
version of the index specifier list provided in the definition of
<code>employee_set</code>. We can prevent this very long name from appearing
in the final type by encapsulating it into another, shorter-named construct:
</p>
<blockquote><pre>
<span class=comment>// reducing symbol names through type hiding
// type hide the index specifier list within employee_set_indices</span>
<span class=keyword>struct</span> <span class=identifier>employee_set_indices</span><span class=special>:</span>
<span class=identifier>indexed_by</span><span class=special>&lt;</span>
<span class=identifier>ordered_unique</span><span class=special>&lt;</span><span class=identifier>identity</span><span class=special>&lt;</span><span class=identifier>employee</span><span class=special>&gt;</span> <span class=special>&gt;,</span>
<span class=identifier>ordered_non_unique</span><span class=special>&lt;</span><span class=identifier>member</span><span class=special>&lt;</span><span class=identifier>employee</span><span class=special>,</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>,&amp;</span><span class=identifier>employee</span><span class=special>::</span><span class=identifier>name</span><span class=special>&gt;</span> <span class=special>&gt;,</span>
<span class=identifier>ordered_unique</span><span class=special>&lt;</span><span class=identifier>member</span><span class=special>&lt;</span><span class=identifier>employee</span><span class=special>,</span><span class=keyword>int</span><span class=special>,&amp;</span><span class=identifier>employee</span><span class=special>::</span><span class=identifier>ssnumber</span><span class=special>&gt;</span> <span class=special>&gt;</span>
<span class=special>&gt;</span>
<span class=special>{};</span>
<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special>&lt;</span>
<span class=identifier>employee</span><span class=special>,</span>
<span class=identifier>employee_set_indices</span>
<span class=special>&gt;</span> <span class=identifier>employee_set</span><span class=special>;</span>
</pre></blockquote>
<p>
<code>employee_set_indices</code> works as a conventional <code>typedef</code>
in all respects, save for a detail: its name does not explicitly
include the information contained in the <code>indexed_by</code> instantiation.
Applying this technique, <code>employee_set::nth_index&lt;0&gt;::type</code>
now becomes:
</p>
<blockquote><pre>
<span class=identifier>boost</span><span class=special>::</span><span class=identifier>multi_index</span><span class=special>::</span><span class=identifier>detail</span><span class=special>::</span><span class=identifier>ordered_index</span><span class=special>&lt;</span>
<span class=identifier>boost</span><span class=special>::</span><span class=identifier>multi_index</span><span class=special>::</span><span class=identifier>identity</span><span class=special>&lt;</span><span class=identifier>employee</span><span class=special>&gt;,</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>less</span><span class=special>&lt;</span><span class=identifier>employee</span><span class=special>&gt;,</span>
<span class=identifier>boost</span><span class=special>::</span><span class=identifier>multi_index</span><span class=special>::</span><span class=identifier>detail</span><span class=special>::</span><span class=identifier>nth_layer</span><span class=special>&lt;</span>
<span class=number>1</span><span class=special>,</span> <span class=identifier>employee</span><span class=special>,</span>
<span class=identifier>employee_set_indices</span><span class=special>,</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>allocator</span><span class=special>&lt;</span><span class=identifier>employee</span><span class=special>&gt;</span>
<span class=special>&gt;,</span>
<span class=identifier>boost</span><span class=special>::</span><span class=identifier>mpl</span><span class=special>::</span><span class=identifier>vector0</span><span class=special>&lt;</span><span class=identifier>mpl_</span><span class=special>::</span><span class=identifier>na</span><span class=special>&gt;,</span>
<span class=identifier>boost</span><span class=special>::</span><span class=identifier>multi_index</span><span class=special>::</span><span class=identifier>detail</span><span class=special>::</span><span class=identifier>ordered_unique_tag</span>
<span class=special>&gt;</span>
</pre></blockquote>
<p>
which is considerably shorter than the original, and also more
easily parsed by a human reader. Type hiding would not work if, instead of
making <code>employee_set_indices</code> a derived <code>struct</code> of
<code>indexed_by&lt;...&gt;</code>, we had defined it as a <code>typedef</code>:
<code>typedef</code>s are syntactic aliases and usually get expanded
by the compiler before doing any further type handling.
</p>
<p>
Type hiding techniques can also be applied to <code>composite_key</code> intantiations,
which often contribute a great deal to symbol name lengths.
</p>
<h2><a name="legacy">Legacy compilers</a></h2>
<p>
Boost.MultiIndex support for legacy compilers is not actively kept, so if you happen
to work with an old environment you might need to use a former version of the library.
A table is provided of some legacy compilers along with the latest version of
Boost.MultiIndex known to work for them (frequently with limitations as explained
in the corresponding compiler specifics section.) If you successfully try one of those
with newer versions of Boost.MultiIndex than stated here, please report back so that
the information can be updated.
</p>
<p align="center">
<table cellspacing="0" cellpadding="5">
<caption><b>Support for legacy compilers.</b></caption>
<tr>
<th>Compiler</th>
<th>Latest known<br>compatible version</th>
<th>Date</th>
</tr>
<tr>
<td>Borland C++ Builder 6.4 through 2006, CodeGear C++Builder 2010</td>
<td>Never worked with Boost.MultiIndex</td>
<td></td>
</tr>
<tr class="odd_tr">
<td>Comeau C/C++ 4.3.10.1 for Windows (VC++ 9.0 backend)</td>
<td><a href="http://www.boost.org/doc/libs/1_38_0/libs/multi_index/doc/compiler_specifics.html#comeau_43101_win_vc7_71">Boost 1.38</a></td>
<td>February 2009</td>
</tr>
<tr>
<td>Compaq C++ 6.5-042 through 7.1-006 for Tru64 UNIX</td>
<td><a href="http://www.boost.org/doc/libs/1_38_0/libs/multi_index/doc/compiler_specifics.html#compaq_65">Boost 1.38</a></td>
<td>February 2009</td>
</tr>
<tr class="odd_tr">
<td>GCC 3.2 through 3.4</td>
<td><a href="http://www.boost.org/doc/libs/1_41_0/libs/multi_index/doc/compiler_specifics.html#gcc_32">Boost 1.41</a></td>
<td>November 2009</td>
</tr>
<tr>
<td>HP aC++ A.06.12 through A.06.17 for HP-UX IA64</td>
<td><a href="http://www.boost.org/doc/libs/1_38_0/libs/multi_index/doc/compiler_specifics.html#acc_612_ia64">Boost 1.38</a></td>
<td>February 2009</td>
</tr>
<tr class="odd_tr">
<td>HP aC++ A.03.80 through A.03.85 for HP-UX PA-RISC</td>
<td><a href="http://www.boost.org/doc/libs/1_38_0/libs/multi_index/doc/compiler_specifics.html#acc_380_pa_risc">Boost 1.38</a></td>
<td>February 2009</td>
</tr>
<tr>
<td>IBM VisualAge C++ V6.0 for AIX</td>
<td><a href="http://www.boost.org/doc/libs/1_33_1/libs/multi_index/doc/compiler_specifics.html#va_60">Boost 1.33.1</a></td>
<td>December 2006</td>
</tr>
<tr class="odd_tr">
<td>IBM XL C/C++ V9.0 through V10.1 for AIX</td>
<td><a href="http://www.boost.org/doc/libs/1_41_0/libs/multi_index/doc/compiler_specifics.html#xl_90">Boost 1.41</a></td>
<td>November 2009</td>
</tr>
<tr>
<td>Intel C++ Compiler for Linux 8.1 through 11.1</td>
<td><a href="http://www.boost.org/doc/libs/1_41_0/libs/multi_index/doc/compiler_specifics.html#intel_81_lin">Boost 1.41</a></td>
<td>November 2009</td>
</tr>
<tr class="odd_tr">
<td>Intel C++ Compiler for Mac OS 9.1 through 11.0</td>
<td><a href="http://www.boost.org/doc/libs/1_41_0/libs/multi_index/doc/compiler_specifics.html#intel_91_mac">Boost 1.41</a></td>
<td>November 2009</td>
</tr>
<tr>
<td>Intel C++ Compiler for Windows 32-bit 8.0 through 11.1</td>
<td><a href="http://www.boost.org/doc/libs/1_41_0/libs/multi_index/doc/compiler_specifics.html#intel_80_win">Boost 1.41</a></td>
<td>November 2009</td>
</tr>
<tr class="odd_tr">
<td>Intel C++ Compiler for Windows 64-bit 10.0 through 11.11</td>
<td><a href="http://www.boost.org/doc/libs/1_41_0/libs/multi_index/doc/compiler_specifics.html#intel_100_win64">Boost 1.41</a></td>
<td>November 2009</td>
</tr>
<tr>
<td>Metrowerks CodeWarrior 8.3</td>
<td><a href="http://www.boost.org/doc/libs/1_36_0/libs/multi_index/doc/compiler_specifics.html#cw_83">Boost 1.36</a></td>
<td>August 2008</td>
</tr>
<tr class="odd_tr">
<td>Metrowerks CodeWarrior 9 through 9.5</td>
<td><a href="http://www.boost.org/doc/libs/1_34_1/libs/multi_index/doc/compiler_specifics.html#cw_9x">Boost 1.34.1</a></td>
<td>July 2007</td>
</tr>
<tr>
<td>Microsoft Visual C++ 6.0 Service Pack 5</td>
<td><a href="http://www.boost.org/doc/libs/1_36_0/libs/multi_index/doc/compiler_specifics.html#msvc_60">Boost 1.36</a></td>
<td>August 2008</td>
</tr>
<tr class="odd_tr">
<td>Microsoft Visual C++ 7.0</td>
<td><a href="http://www.boost.org/doc/libs/1_35_0/libs/multi_index/doc/compiler_specifics.html#msvc_70">Boost 1.35</a></td>
<td>March 2008</td>
</tr>
<tr>
<td>Sun Studio 10 through 12 Update 1 for Solaris</td>
<td><a href="http://www.boost.org/doc/libs/1_41_0/libs/multi_index/doc/compiler_specifics.html#sun_10">Boost 1.41</a></td>
<td>November 2009</td>
</tr>
</table>
</p>
<hr>
<div class="prev_link"><a href="reference/key_extraction.html"><img src="prev.gif" alt="key extraction" border="0"><br>
Key extraction
</a></div>
<div class="up_link"><a href="index.html"><img src="up.gif" alt="index" border="0"><br>
Index
</a></div>
<div class="next_link"><a href="performance.html"><img src="next.gif" alt="performance" border="0"><br>
Performance
</a></div><br clear="all" style="clear: all;">
<br>
<p>Revised August 20th 2014</p>
<p>&copy; Copyright 2003-2014 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz.
Distributed under the Boost Software
License, Version 1.0. (See accompanying file <a href="../../../LICENSE_1_0.txt">
LICENSE_1_0.txt</a> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">
http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</body>
</html>

View File

@@ -0,0 +1,463 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0.1 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Boost.MultiIndex Documentation - Examples</title>
<link rel="stylesheet" href="style.css" type="text/css">
<link rel="start" href="index.html">
<link rel="prev" href="performance.html">
<link rel="up" href="index.html">
<link rel="next" href="tests.html">
</head>
<body>
<h1><img src="../../../boost.png" alt="boost.png (6897 bytes)" align=
"middle" width="277" height="86">Boost.MultiIndex Examples</h1>
<div class="prev_link"><a href="performance.html"><img src="prev.gif" alt="performance" border="0"><br>
Performance
</a></div>
<div class="up_link"><a href="index.html"><img src="up.gif" alt="index" border="0"><br>
Index
</a></div>
<div class="next_link"><a href="tests.html"><img src="next.gif" alt="tests" border="0"><br>
Tests
</a></div><br clear="all" style="clear: all;">
<hr>
<h2>Contents</h2>
<ul>
<li><a href="#example1">Example 1: basic usage</a></li>
<li><a href="#example2">Example 2: using functions as keys</a></li>
<li><a href="#example3">Example 3: constructing <code>multi_index_container</code>s
with <code>ctor_args_list</code></a></li>
<li><a href="#example4">Example 4: bidirectional map</a></li>
<li><a href="#example5">Example 5: sequenced indices</a></li>
<li><a href="#example6">Example 6: complex searches and foreign keys</a></li>
<li><a href="#example7">Example 7: composite keys</a></li>
<li><a href="#example8">Example 8: hashed indices</a></li>
<li><a href="#example9">Example 9: serialization and MRU lists</a></li>
<li><a href="#example10">Example 10: random access indices</a></li>
<li><a href="#example11">Example 11: index rearrangement</a></li>
<li><a href="#example12">Example 12: using Boost.Interprocess allocators</a></li>
</ul>
<h2><a name="example1">Example 1: basic usage</a></h2>
<p>
See <a href="../example/basic.cpp">source code</a>.
</p>
<p>
Basic program showing the multi-indexing capabilities of Boost.MultiIndex
with an admittedly boring set of <code>employee</code> records.
</p>
<h2><a name="example2">Example 2: using functions as keys</a></h2>
<p>
See <a href="../example/fun_key.cpp">source code</a>.
</p>
<p>
Usually keys assigned to an index are based on a member variable of the
element, but key extractors can be defined which take their value from
a member function or a global function. This has some similarity with the concept of
<i>calculated keys</i> supported by some relational database engines.
The example shows how to use the predefined <code>const_mem_fun</code>
and <code>global_fun</code> key extractors to deal with this situation.
</p>
<p>
Keys based on functions usually will not be actual references,
but rather the temporary values resulting from the invocation of the
member function used. This implies that <code>modify_key</code> cannot be
applied to this type of extractors, which is a perfectly logical
constraint anyway.
</p>
<h2><a name="example3">Example 3: constructing <code>multi_index_container</code>s
with <code>ctor_args_list</code></a></h2>
<p>
See <a href="../example/non_default_ctor.cpp">source code</a>.
</p>
<p>
We show a practical example of usage of <code>multi_index_container::ctor_arg_list</code>,
whose definition and purpose are explained in the
<a href="tutorial/creation.html#ctor_args_list">tutorial</a>. The
program groups a sorted collection of numbers based on identification through
modulo arithmetics, by which <code>x</code> and <code>y</code> are equivalent
if <code>(x%n)==(y%n)</code>, for some fixed <code>n</code>.
</p>
<h2><a name="example4">Example 4: bidirectional map</a></h2>
<p>
See <a href="../example/bimap.cpp">source code</a>.
</p>
<p>
This example shows how to construct a bidirectional map with
<code>multi_index_container</code>. By a <i>bidirectional map</i> we mean
a container of <code>(const FromType,const ToType)</code> pairs
such that no two elements exists with the same first
<i>or</i> second component (<code>std::map</code> only
guarantees uniqueness of the first component). Fast lookup is provided
for both keys. The program features a tiny Spanish-English
dictionary with online query of words in both languages.
</p>
<p>
This bidirectional map can be considered as a primitive precursor
to the full-fledged container provided by
<a href="../../bimap/index.html">Boost.Bimap</a>.
</p>
<h2><a name="example5">Example 5: sequenced indices</a></h2>
<p>
See <a href="../example/sequenced.cpp">source code</a>.
</p>
<p>
The combination of a sequenced index with an index of type <code>ordered_non_unique</code>
yields a <code>list</code>-like structure with fast lookup capabilities. The
example performs some operations on a given text, like word counting and
selective deletion of some words.
</p>
<h2><a name="example6">Example 6: complex searches and foreign keys</a></h2>
<p>
See <a href="../example/complex_structs.cpp">source code</a>.
</p>
<p>
This program illustrates some advanced techniques that can be applied
for complex data structures using <code>multi_index_container</code>.
Consider a <code>car_model</code> class for storing information
about automobiles. On a first approach, <code>car_model</code> can
be defined as:
</p>
<blockquote><pre>
<span class=keyword>struct</span> <span class=identifier>car_model</span>
<span class=special>{</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span> <span class=identifier>model</span><span class=special>;</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span> <span class=identifier>manufacturer</span><span class=special>;</span>
<span class=keyword>int</span> <span class=identifier>price</span><span class=special>;</span>
<span class=special>};</span>
</pre></blockquote>
<p>
This definition has a design flaw that any reader acquainted with
relational databases can easily spot: The <code>manufacturer</code>
member is duplicated among all cars having the same manufacturer.
This is a waste of space and poses difficulties when, for instance,
the name of a manufacturer has to be changed. Following the usual
principles in relational database design, the appropriate design
involves having the manufactures stored in a separate
<code>multi_index_container</code> and store pointers to these in
<code>car_model</code>:
</p>
<blockquote><pre>
<span class=keyword>struct</span> <span class=identifier>car_manufacturer</span>
<span class=special>{</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span> <span class=identifier>name</span><span class=special>;</span>
<span class=special>};</span>
<span class=keyword>struct</span> <span class=identifier>car_model</span>
<span class=special>{</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span> <span class=identifier>model</span><span class=special>;</span>
<span class=identifier>car_manufacturer</span><span class=special>*</span> <span class=identifier>manufacturer</span><span class=special>;</span>
<span class=keyword>int</span> <span class=identifier>price</span><span class=special>;</span>
<span class=special>};</span>
</pre></blockquote>
<p>
Although predefined Boost.MultiIndex key extractors can handle many
situations involving pointers (see
<a href="tutorial/key_extraction.html#advanced_key_extractors">advanced features
of Boost.MultiIndex key extractors</a> in the tutorial), this case
is complex enough that a suitable key extractor has to be defined. The following
utility cascades two key extractors:
</p>
<blockquote><pre>
<span class=keyword>template</span><span class=special>&lt;</span><span class=keyword>class</span> <span class=identifier>KeyExtractor1</span><span class=special>,</span><span class=keyword>class</span> <span class=identifier>KeyExtractor2</span><span class=special>&gt;</span>
<span class=keyword>struct</span> <span class=identifier>key_from_key</span>
<span class=special>{</span>
<span class=keyword>public</span><span class=special>:</span>
<span class=keyword>typedef</span> <span class=keyword>typename</span> <span class=identifier>KeyExtractor1</span><span class=special>::</span><span class=identifier>result_type</span> <span class=identifier>result_type</span><span class=special>;</span>
<span class=identifier>key_from_key</span><span class=special>(</span>
<span class=keyword>const</span> <span class=identifier>KeyExtractor1</span><span class=special>&amp;</span> <span class=identifier>key1_</span><span class=special>=</span><span class=identifier>KeyExtractor1</span><span class=special>(),</span>
<span class=keyword>const</span> <span class=identifier>KeyExtractor2</span><span class=special>&amp;</span> <span class=identifier>key2_</span><span class=special>=</span><span class=identifier>KeyExtractor2</span><span class=special>()):</span>
<span class=identifier>key1</span><span class=special>(</span><span class=identifier>key1_</span><span class=special>),</span><span class=identifier>key2</span><span class=special>(</span><span class=identifier>key2_</span><span class=special>)</span>
<span class=special>{}</span>
<span class=keyword>template</span><span class=special>&lt;</span><span class=keyword>typename</span> <span class=identifier>Arg</span><span class=special>&gt;</span>
<span class=identifier>result_type</span> <span class=keyword>operator</span><span class=special>()(</span><span class=identifier>Arg</span><span class=special>&amp;</span> <span class=identifier>arg</span><span class=special>)</span><span class=keyword>const</span>
<span class=special>{</span>
<span class=keyword>return</span> <span class=identifier>key1</span><span class=special>(</span><span class=identifier>key2</span><span class=special>(</span><span class=identifier>arg</span><span class=special>));</span>
<span class=special>}</span>
<span class=keyword>private</span><span class=special>:</span>
<span class=identifier>KeyExtractor1</span> <span class=identifier>key1</span><span class=special>;</span>
<span class=identifier>KeyExtractor2</span> <span class=identifier>key2</span><span class=special>;</span>
<span class=special>};</span>
</pre></blockquote>
<p>
so that access from a <code>car_model</code> to the <code>name</code> field
of its associated <code>car_manufacturer</code> can be accomplished with
</p>
<blockquote><pre>
<span class=identifier>key_from_key</span><span class=special>&lt;</span>
<span class=identifier>member</span><span class=special>&lt;</span><span class=identifier>car_manufacturer</span><span class=special>,</span><span class=keyword>const</span> <span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>,&amp;</span><span class=identifier>car_manufacturer</span><span class=special>::</span><span class=identifier>name</span><span class=special>&gt;,</span>
<span class=identifier>member</span><span class=special>&lt;</span><span class=identifier>car_model</span><span class=special>,</span><span class=keyword>const</span> <span class=identifier>car_manufacturer</span> <span class=special>*,</span><span class=identifier>car_model</span><span class=special>::</span><span class=identifier>manufacturer</span><span class=special>&gt;</span>
<span class=special>&gt;</span>
</pre></blockquote>
<p>
The program asks the user for a car manufacturer and a range of prices
and returns the car models satisfying these requirements. This is a complex
search that cannot be performed on a single operation. Broadly sketched,
one procedure for executing the selection is:
<ol>
<li>Select the elements with the given manufacturer by means
of <code>equal_range</code>,
<li>feed these elements into a <code>multi_index_container</code> sorted
by price,
<li>select by price using <code>lower_bound</code> and
<code>upper_bound</code>;
</ol>
or alternatively:
<ol>
<li>Select the elements within the price range with
<code>lower_bound</code> and <code>upper_bound</code>,
<li>feed these elements into a <code>multi_index_container</code> sorted
by manufacturer,
<li>locate the elements with given manufacturer using
<code>equal_range</code>.
</ol>
An interesting technique developed in the example lies in
the construction of the intermediate <code>multi_index_container</code>.
In order to avoid object copying, appropriate <i>view</i> types
are defined with <code>multi_index_container</code>s having as elements
pointers to <code>car_model</code>s instead of actual objects.
These views have to be supplemented with appropriate
dereferencing key extractors.
</p>
<h2><a name="example7">Example 7: composite keys</a></h2>
<p>
See <a href="../example/composite_keys.cpp">source code</a>.
</p>
<p>
Boost.MultiIndex <a href="tutorial/key_extraction.html#composite_keys">
<code>composite_key</code></a> construct provides a flexible tool for
creating indices with non-trivial sorting criteria.
The program features a rudimentary simulation of a file system
along with an interactive Unix-like shell. A file entry is represented by
the following structure:
</p>
<blockquote><pre>
<span class=keyword>struct</span> <span class=identifier>file_entry</span>
<span class=special>{</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span> <span class=identifier>name</span><span class=special>;</span>
<span class=keyword>unsigned</span> <span class=identifier>size</span><span class=special>;</span>
<span class=keyword>bool</span> <span class=identifier>is_dir</span><span class=special>;</span> <span class=comment>// true if the entry is a directory</span>
<span class=keyword>const</span> <span class=identifier>file_entry</span><span class=special>*</span> <span class=identifier>dir</span><span class=special>;</span> <span class=comment>// directory this entry belongs in</span>
<span class=special>};</span>
</pre></blockquote>
<p>
Entries are kept in a <code>multi_index_container</code> maintaining two indices
with composite keys:
<ul>
<li>A primary index ordered by directory and name,</li>
<li>a secondary index ordered by directory and size.</li>
</ul>
The reason that the order is made firstly by the directory in which
the files are located obeys to the local nature of the shell commands,
like for instance <code>ls</code>. The shell simulation only has three
commands:
<ul>
<li><code>cd [.|..|<i>&lt;directory&gt;</i>]</code></li>
<li><code>ls [-s]</code> (<code>-s</code> orders the output by size)</li>
<li><code>mkdir <i>&lt;directory&gt;</i></code></li>
</ul>
The program exits when the user presses the Enter key at the command prompt.
</p>
<p>
The reader is challenged to add more functionality to the program; for
instance:
<ul>
<li>Implement additional commands, like <code>cp</code>.</li>
<li>Add handling of absolute paths.</li>
<li>Use <a href="tutorial/creation.html#serialization">serialization</a>
to store and retrieve the filesystem state between program runs.</li>
</ul>
</p>
<h2><a name="example8">Example 8: hashed indices</a></h2>
<p>
See <a href="../example/hashed.cpp">source code</a>.
</p>
<p>
Hashed indices can be used as an alternative to ordered indices when
fast lookup is needed and sorting information is of no interest. The
example features a word counter where duplicate entries are checked
by means of a hashed index. Confront the word counting algorithm with
that of <a href="#example5">example 5</a>.
</p>
<h2><a name="example9">Example 9: serialization and MRU lists</a></h2>
<p>
See <a href="../example/serialization.cpp">source code</a>.
</p>
<p>
A typical application of serialization capabilities allows a program to
restore the user context between executions. The example program asks
the user for words and keeps a record of the ten most recently entered
ones, in the current or in previous sessions. The serialized data structure,
sometimes called an <i>MRU (most recently used) list</i>, has some interest
on its own: an MRU list behaves as a regular FIFO queue, with the exception
that, when inserting a preexistent entry, this does not appear twice, but
instead the entry is moved to the front of the list. You can observe this
behavior in many programs featuring a "Recent files" menu command. This
data structure is implemented with <code>multi_index_container</code> by
combining a sequenced index and an index of type <code>hashed_unique</code>.
</p>
<h2><a name="example10">Example 10: random access indices</a></h2>
<p>
See <a href="../example/random_access.cpp">source code</a>.
</p>
<p>
The example resumes the text container introduced in
<a href="#example5">example 5</a> and shows how substituting a random
access index for a sequenced index allows for extra capabilities like
efficient access by position and calculation of the offset of a given
element into the container.
</p>
<h2><a name="example11">Example 11: index rearrangement</a></h2>
<p>
See <a href="../example/rearrange.cpp">source code</a>.
</p>
<p>
There is a relatively common piece of urban lore claiming that
a deck of cards must be shuffled seven times in a row to be perfectly
mixed. The statement derives from the works of mathematician Persi
Diaconis on <i>riffle shuffling</i>: this shuffling
technique involves splitting the deck in two packets roughly the same
size and then dropping the cards from both packets so that they become
interleaved. It has been shown that when repeating this procedure
seven times the statistical distribution of cards is reasonably
close to that associated with a truly random permutation. A measure
of "randomness" can be estimated by counting <i>rising sequences</i>:
consider a permutation of the sequence 1,2, ... , <i>n</i>, a rising sequence
is a maximal chain of consecutive elements <i>m</i>, <i>m+1</i>, ... , <i>m+r</i>
such that they are arranged in ascending order. For instance, the permutation
125364789 is composed of the two rising sequences 1234 and 56789,
as becomes obvious by displaying the sequence like this,
<span style="vertical-align:sub">1</span><span style="vertical-align:sub">2</span><span style="vertical-align:super">5</span><span style="vertical-align:sub">3</span><span style="vertical-align:super">6</span><span style="vertical-align:sub">4</span><span style="vertical-align:super">7</span><span style="vertical-align:super">8</span><span style="vertical-align:super">9</span>.
The average number of rising sequences in a random permutation of
<i>n</i> elements is (<i>n</i>+1)/2: by contrast, after a single riffle
shuffle of an initially sorted deck of cards, there cannot be more than
two rising sequences. The average number of rising sequences approximates
to (<i>n</i>+1)/2 as the number of consecutive riffle shuffles increases,
with seven shuffles yielding a close result for a 52-card poker deck.
Brad Mann's paper
<a href="http://www.dartmouth.edu/~chance/teaching_aids/books_articles/Mann.pdf">"How
many times should you shuffle a deck of cards?"</a> provides a
rigorous yet very accessible treatment of this subject.
</p>
<p>
The example program estimates the average number of rising sequences
in a 52-card deck after repeated riffle shuffling as well as applying
a completely random permutation. The deck is modeled by the following
container:
<blockquote><pre>
<span class=identifier>multi_index_container</span><span class=special>&lt;</span>
<span class=keyword>int</span><span class=special>,</span>
<span class=identifier>indexed_by</span><span class=special>&lt;</span>
<span class=identifier>random_access</span><span class=special>&lt;&gt;,</span>
<span class=identifier>random_access</span><span class=special>&lt;&gt;</span>
<span class=special>&gt;</span>
<span class=special>&gt;</span>
</pre></blockquote>
where the first index stores the current arrangement of the deck, while
the second index is used to remember the start position. This representation
allows for an efficient implementation of a rising sequences counting
algorithm in linear time.
<a href="reference/rnd_indices.html#rearrange"><code>rearrange</code></a>
is used to apply to the deck a shuffle performed externally on an
auxiliary data structure.
</p>
<h2><a name="example12">Example 12: using Boost.Interprocess allocators</a></h2>
<p>
See <a href="../example/ip_allocator.cpp">source code</a>.
</p>
<p>
Boost.MultiIndex supports special allocators such as those provided by
<a href="../../interprocess/index.html">Boost.Interprocess</a>,
which allows for <code>multi_index_container</code>s to be placed in shared
memory. The example features a front-end to a small book database
implemented by means of a <code>multi_index_container</code> stored
in a Boost.Interprocess memory mapped file. The reader can verify that several
instances of the program correctly work simultaneously and immediately see
the changes to the database performed by any other instance.
</p>
<hr>
<div class="prev_link"><a href="performance.html"><img src="prev.gif" alt="performance" border="0"><br>
Performance
</a></div>
<div class="up_link"><a href="index.html"><img src="up.gif" alt="index" border="0"><br>
Index
</a></div>
<div class="next_link"><a href="tests.html"><img src="next.gif" alt="tests" border="0"><br>
Tests
</a></div><br clear="all" style="clear: all;">
<br>
<p>Revised May 26th 2009</p>
<p>&copy; Copyright 2003-2009 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz.
Distributed under the Boost Software
License, Version 1.0. (See accompanying file <a href="../../../LICENSE_1_0.txt">
LICENSE_1_0.txt</a> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">
http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</body>
</html>

View File

@@ -0,0 +1,199 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0.1 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Boost.MultiIndex Documentation - Future work</title>
<link rel="stylesheet" href="style.css" type="text/css">
<link rel="start" href="index.html">
<link rel="prev" href="tests.html">
<link rel="up" href="index.html">
<link rel="next" href="release_notes.html">
</head>
<body>
<h1><img src="../../../boost.png" alt="boost.png (6897 bytes)" align=
"middle" width="277" height="86">Boost.MultiIndex Future work</h1>
<div class="prev_link"><a href="tests.html"><img src="prev.gif" alt="tests" border="0"><br>
Tests
</a></div>
<div class="up_link"><a href="index.html"><img src="up.gif" alt="index" border="0"><br>
Index
</a></div>
<div class="next_link"><a href="release_notes.html"><img src="next.gif" alt="release notes" border="0"><br>
Release notes
</a></div><br clear="all" style="clear: all;">
<hr>
<p>
A number of new functionalities are considered for inclusion into
future releases of Boost.MultiIndex. Some of them depend on the
potential for extensibility of the library, which has been a guiding
principle driving the current internal design of <code>multi_index_container</code>.
</p>
<h2>Contents</h2>
<ul>
<li><a href="#notifying">Notifying indices</a></li>
<li><a href="#constraints">Constraints</a></li>
<li><a href="#user_defined_indices">User-defined indices</a></li>
<li><a href="#indexed_maps">Indexed maps</a></li>
</ul>
<h2><a name="notifying">Notifying indices</a></h2>
<p>
<i>Notifying indices</i> can be implemented as decorators over
preexistent index types, with the added functionality that internal
events of the index (insertion, erasing, modifying of elements) are
signalled to an external entity --for instance, by means of the
<a href="../../../doc/html/signals.html">Boost.Signals</a>
library. This functionality can have applications for:
<ol>
<li>Logging,</li>
<li>interfacing to GUI-based applications,</li>
<li>synchronization between separate data structures.</li>
</ol>
</p>
<p>
The following is a sketch of a possible realization of notifying
indices:
</p>
<blockquote><pre>
<span class=keyword>struct</span> <span class=identifier>insert_log</span>
<span class=special>{</span>
<span class=keyword>void</span> <span class=keyword>operator</span><span class=special>()(</span><span class=keyword>int</span> <span class=identifier>x</span><span class=special>)</span>
<span class=special>{</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>clog</span><span class=special>&lt;&lt;</span><span class=string>&quot;insert: &quot;</span><span class=special>&lt;&lt;</span><span class=identifier>x</span><span class=special>&lt;&lt;</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>endl</span><span class=special>;</span>
<span class=special>}</span>
<span class=special>};</span>
<span class=keyword>int</span> <span class=identifier>main</span><span class=special>()</span>
<span class=special>{</span>
<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special>&lt;</span>
<span class=keyword>int</span><span class=special>,</span>
<span class=identifier>indexed_by</span><span class=special>&lt;</span>
<span class=identifier>notifying</span><span class=special>&lt;</span><span class=identifier>ordered_unique</span><span class=special>&lt;</span><span class=identifier>identity</span><span class=special>&lt;</span><span class=keyword>int</span><span class=special>&gt;</span> <span class=special>&gt;</span> <span class=special>&gt;,</span> <span class=comment>// notifying index</span>
<span class=identifier>ordered_non_unique</span><span class=special>&lt;</span><span class=identifier>identity</span><span class=special>&lt;</span><span class=keyword>int</span><span class=special>&gt;</span> <span class=special>&gt;</span>
<span class=special>&gt;</span>
<span class=special>&gt;</span> <span class=identifier>indexed_t</span><span class=special>;</span>
<span class=identifier>indexed_t</span> <span class=identifier>t</span><span class=special>;</span>
<span class=comment>// on_insert is the signal associated to insertions</span>
<span class=identifier>t</span><span class=special>.</span><span class=identifier>on_insert</span><span class=special>.</span><span class=identifier>connect</span><span class=special>(</span><span class=identifier>insert_log</span><span class=special>());</span>
<span class=identifier>t</span><span class=special>.</span><span class=identifier>insert</span><span class=special>(</span><span class=number>0</span><span class=special>);</span>
<span class=identifier>t</span><span class=special>.</span><span class=identifier>insert</span><span class=special>(</span><span class=number>1</span><span class=special>);</span>
<span class=keyword>return</span> <span class=number>0</span><span class=special>;</span>
<span class=special>}</span>
<span class=comment>// output:
// insert: 0
// insert: 1</span>
</pre></blockquote>
<h2><a name="constraints">Constraints</a></h2>
<p>
The notifying indices functionality described above exploits a powerful
design pattern based on <i>index adaptors</i>, decorators over preexistent
indices which add some functionality or somehow change the semantics of
the underlying index. This pattern can be used for the implementation
of <i>constraints</i>, adaptors that restrict the elements accepted by an
index according to some validation predicate. The following is a possible
realization of how constraints syntax may look like:
</p>
<blockquote><pre>
<span class=keyword>struct</span> <span class=identifier>is_even</span>
<span class=special>{</span>
<span class=keyword>bool</span> <span class=keyword>operator</span><span class=special>()(</span><span class=keyword>int</span> <span class=identifier>x</span><span class=special>)</span><span class=keyword>const</span><span class=special>{</span><span class=keyword>return</span> <span class=identifier>x</span><span class=special>%</span><span class=number>2</span><span class=special>==</span><span class=number>0</span><span class=special>;}</span>
<span class=special>};</span>
<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special>&lt;</span>
<span class=keyword>int</span><span class=special>,</span>
<span class=identifier>indexed_by</span><span class=special>&lt;</span>
<span class=identifier>constrained</span><span class=special>&lt;</span><span class=identifier>ordered_unique</span><span class=special>&lt;</span><span class=identifier>identity</span><span class=special>&lt;</span><span class=keyword>int</span><span class=special>&gt;</span> <span class=special>&gt;,</span><span class=identifier>is_even</span><span class=special>&gt;</span>
<span class=special>&gt;</span>
<span class=special>&gt;</span> <span class=identifier>indexed_t</span><span class=special>;</span>
</pre></blockquote>
<h2><a name="user_defined_indices">User-defined indices</a></h2>
<p>
The mechanisms by which Boost.MultiIndex orchestrates the
operations of the indices held by a <code>multi_index_container</code> are
simple enough to make them worth documenting so that the (bold)
user can write implementations for her own indices.
</p>
<h2><a name="indexed_maps">Indexed maps</a></h2>
<p>
<code>multi_index_container</code> is rich enough to provide the basis
for implementation of <i>indexed maps</i>, i.e. maps which
can be looked upon several different keys. The motivation for having
such a container is mainly aesthetic convenience, since it
would not provide any additional feature to similar constructs
based directly on <code>multi_index_container</code>.
</p>
<p>
The main challenge in writing an indexed map lies in the design of a
reasonable interface that resembles that of <code>std::map</code> as
much as possible. There seem to be fundamental difficulties in extending
the syntax of a <code>std::map</code> to multiple keys. For one example,
consider the situation:
</p>
<blockquote><pre>
<span class=identifier>indexed_map</span><span class=special>&lt;</span><span class=keyword>int</span><span class=special>,</span><span class=identifier>string</span><span class=special>,</span><span class=keyword>double</span><span class=special>&gt;</span> <span class=identifier>m</span><span class=special>;</span>
<span class=comment>// keys are int and string, double is the mapped to value</span>
<span class=special>...</span>
<span class=identifier>cout</span><span class=special>&lt;&lt;</span><span class=identifier>m</span><span class=special>[</span><span class=number>0</span><span class=special>]&lt;&lt;</span><span class=identifier>endl</span><span class=special>;</span> <span class=comment>// OK</span>
<span class=identifier>cout</span><span class=special>&lt;&lt;</span><span class=identifier>m</span><span class=special>[</span><span class=string>&quot;zero&quot;</span><span class=special>]&lt;&lt;</span><span class=identifier>endl</span><span class=special>;</span> <span class=comment>// OK</span>
<span class=identifier>m</span><span class=special>[</span><span class=number>1</span><span class=special>]=</span><span class=number>1.0</span><span class=special>;</span> <span class=comment>// !!</span>
</pre></blockquote>
<p>
In the last sentence of the example, the user has no way of
providing the <code>string</code> key mapping to the same value
as <code>m[1]</code>. This and similar problems have to be devoted
a careful study when designing the interface of a potential
indexed map.
</p>
<hr>
<div class="prev_link"><a href="tests.html"><img src="prev.gif" alt="tests" border="0"><br>
Tests
</a></div>
<div class="up_link"><a href="index.html"><img src="up.gif" alt="index" border="0"><br>
Index
</a></div>
<div class="next_link"><a href="release_notes.html"><img src="next.gif" alt="release notes" border="0"><br>
Release notes
</a></div><br clear="all" style="clear: all;">
<br>
<p>Revised April 19th 2015</p>
<p>&copy; Copyright 2003-2015 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz.
Distributed under the Boost Software
License, Version 1.0. (See accompanying file <a href="../../../LICENSE_1_0.txt">
LICENSE_1_0.txt</a> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">
http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

View File

@@ -0,0 +1,99 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0.1 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Boost.MultiIndex Documentation - Index</title>
<link rel="stylesheet" href="style.css" type="text/css">
<link rel="start" href="index.html">
<link rel="next" href="tutorial/index.html">
</head>
<body>
<h1><img src="../../../boost.png" alt="boost.png (6897 bytes)" align=
"middle" width="277" height="86">Boost Multi-index Containers Library</h1>
<div class="prev_link">&nbsp;</div>
<div class="up_link">&nbsp;</div>
<div class="next_link"><a href="tutorial/index.html"><img src="next.gif" alt="tutorial" border="0"><br>
Tutorial
</a></div><br clear="all" style="clear: all;">
<hr>
<p>
The Boost Multi-index Containers Library provides a class template named
<code>multi_index_container</code> which enables the construction of containers
maintaining one or more <i>indices</i> with different sorting and access semantics.
Indices provide interfaces similar to those of STL containers, making using them
familiar. The concept of multi-indexing over the same collection of elements is
borrowed from relational database terminology and allows for the specification of
complex data structures in the spirit of multiply indexed relational tables where
simple sets and maps are not enough. A wide selection of indices is provided,
modeled after analogous STL containers like <code>std::set</code>,
<code>std::list</code> and <code>std::unordered_set</code>.
</p>
<p>
Boost.MultiIndex features additional functionalities, like subobject searching,
range querying, in-place updating of elements and calculation of ranks,
which make it a convenient replacement
for <code>std::set</code> and <code>set::multiset</code> even when no multi-indexing
capabilities are needed.
</p>
<p>
The versatile nature of Boost.MultiIndex allows for the specification of
a wide spectrum of different data structures. The following are possible
examples of use developed in the documentation:
<ul>
<li><a href="tutorial/basics.html#multiple_sort">Sets with several iteration orders
and search criteria</a>.</li>
<li><a href="tutorial/basics.html#list_fast_lookup">Lists with fast lookup</a>
and/or without duplicates.</li>
<li><a href="examples.html#example4">Bidirectional maps</a>, i.e. maps
searchable either for key or value.</li>
<li><a href="examples.html#example9">MRU (most recently used) lists</a>,
structures keeping the <i>n</i> last referenced items, beginning with
the newest ones.</li>
<li><a href="tutorial/techniques.html#emulate_std_containers">Emulations of
standard containers</a> taking advantage of the extra functionalities
provided by Boost.MultiIndex.</li>
</ul>
</p>
<h2>Contents</h2>
<ul>
<li><a href="tutorial/index.html">Tutorial</a></li>
<li><a href="reference/index.html">Reference</a></li>
<li><a href="compiler_specifics.html">Compiler specifics</a></li>
<li><a href="performance.html">Performance</a></li>
<li><a href="examples.html">Examples</a></li>
<li><a href="tests.html">Tests</a></li>
<li><a href="future_work.html">Future work</a></li>
<li><a href="release_notes.html">Release notes</a></li>
<li><a href="acknowledgements.html">Acknowledgements</a></li>
</ul>
<hr>
<div class="prev_link">&nbsp;</div>
<div class="up_link">&nbsp;</div>
<div class="next_link"><a href="tutorial/index.html"><img src="next.gif" alt="tutorial" border="0"><br>
Tutorial
</a></div><br clear="all" style="clear: all;">
<br>
<p>Revised April 19th 2015</p>
<p>&copy; Copyright 2003-2015 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz.
Distributed under the Boost Software
License, Version 1.0. (See accompanying file <a href="../../../LICENSE_1_0.txt">
LICENSE_1_0.txt</a> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">
http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 852 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

View File

@@ -0,0 +1,762 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0.1 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Boost.MultiIndex Documentation - Performance</title>
<link rel="stylesheet" href="style.css" type="text/css">
<link rel="start" href="index.html">
<link rel="prev" href="compiler_specifics.html">
<link rel="up" href="index.html">
<link rel="next" href="examples.html">
</head>
<body>
<h1><img src="../../../boost.png" alt="boost.png (6897 bytes)" align=
"middle" width="277" height="86">Boost.MultiIndex Performance</h1>
<div class="prev_link"><a href="compiler_specifics.html"><img src="prev.gif" alt="compiler specifics" border="0"><br>
Compiler specifics
</a></div>
<div class="up_link"><a href="index.html"><img src="up.gif" alt="index" border="0"><br>
Index
</a></div>
<div class="next_link"><a href="examples.html"><img src="next.gif" alt="examples" border="0"><br>
Examples
</a></div><br clear="all" style="clear: all;">
<hr>
<h2>Contents</h2>
<ul>
<li><a href="#intro">Introduction</a></li>
<li><a href="#simulation">Manual simulation of a <code>multi_index_container</code></a></li>
<li><a href="#spatial_efficiency">Spatial efficiency</a></li>
<li><a href="#time_efficiency">Time efficiency</a></li>
<li><a href="#tests">Performance tests</a>
<ul>
<li><a href="#test_1r">Results for 1 ordered index</a>
<ul>
<li><a href="#memory_1r">Memory consumption</a></li>
<li><a href="#time_1r">Execution time</a></li>
</ul>
</li>
<li><a href="#test_1s">Results for 1 sequenced index</a>
<ul>
<li><a href="#memory_1s">Memory consumption</a></li>
<li><a href="#time_1s">Execution time</a></li>
</ul>
</li>
<li><a href="#test_2r">Results for 2 ordered indices</a>
<ul>
<li><a href="#memory_2r">Memory consumption</a></li>
<li><a href="#time_2r">Execution time</a></li>
</ul>
</li>
<li><a href="#test_1r1s">Results for 1 ordered index + 1 sequenced index</a>
<ul>
<li><a href="#memory_1r1s">Memory consumption</a></li>
<li><a href="#time_1r1s">Execution time</a></li>
</ul>
</li>
<li><a href="#test_3r">Results for 3 ordered indices</a>
<ul>
<li><a href="#memory_3r">Memory consumption</a></li>
<li><a href="#time_3r">Execution time</a></li>
</ul>
</li>
<li><a href="#test_2r1s">Results for 2 ordered indices + 1 sequenced index</a>
<ul>
<li><a href="#memory_2r1s">Memory consumption</a></li>
<li><a href="#time_2r1s">Execution time</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#conclusions">Conclusions</a></li>
</ul>
<h2><a name="intro">Introduction</a></h2>
<p>
Boost.MultiIndex helps the programmer to avoid the manual construction of cumbersome
compositions of containers when multi-indexing capabilities are needed. Furthermore,
it does so in an efficient manner, both in terms of space and time consumption. The
space savings stem from the compact representation of the underlying data structures,
requiring a single node per element. As for time efficiency, Boost.MultiIndex
intensively uses metaprogramming techniques producing very tight implementations
of member functions which take care of the elementary operations for each index:
for <code>multi_index_container</code>s with two or more indices, the running time
can be reduced to half as long as with manual simulations involving several
STL containers.
</p>
<h2><a name="simulation">Manual simulation of a <code>multi_index_container</code></a></h2>
<p>
The section on <a href="tutorial/techniques.html#emulate_std_containers">emulation
of standard containers with <code>multi_index_container</code></a> shows the equivalence
between single-index <code>multi_index_container</code>s and some STL containers. Let us now
concentrate on the problem of simulating a <code>multi_index_container</code> with two
or more indices with a suitable combination of standard containers.
</p>
<p>
Consider the following instantiation of <code>multi_index_container</code>:
</p>
<blockquote><pre>
<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special>&lt;</span>
<span class=keyword>int</span><span class=special>,</span>
<span class=identifier>indexed_by</span><span class=special>&lt;</span>
<span class=identifier>ordered_unique</span><span class=special>&lt;</span><span class=identifier>identity</span><span class=special>&lt;</span><span class=keyword>int</span><span class=special>&gt;</span> <span class=special>&gt;,</span>
<span class=identifier>ordered_non_unique</span><span class=special>&lt;</span><span class=identifier>identity</span><span class=special>&lt;</span><span class=keyword>int</span><span class=special>&gt;,</span> <span class=identifier>std</span><span class=special>::</span><span class=identifier>greater</span> <span class=special>&gt;,</span>
<span class=special>&gt;</span>
<span class=special>&gt;</span> <span class=identifier>indexed_t</span><span class=special>;</span>
</pre></blockquote>
<p>
<code>indexed_t</code> maintains two internal indices on elements of type
<code>int</code>. In order to simulate this data structure resorting only to
standard STL containers, one can use on a first approach the following types:
</p>
<blockquote><pre>
<span class=comment>// dereferencing compare predicate</span>
<span class=keyword>template</span><span class=special>&lt;</span><span class=keyword>typename</span> <span class=identifier>Iterator</span><span class=special>,</span><span class=keyword>typename</span> <span class=identifier>Compare</span><span class=special>&gt;</span>
<span class=keyword>struct</span> <span class=identifier>it_compare</span>
<span class=special>{</span>
<span class=keyword>bool</span> <span class=keyword>operator</span><span class=special>()(</span><span class=keyword>const</span> <span class=identifier>Iterator</span><span class=special>&amp;</span> <span class=identifier>x</span><span class=special>,</span><span class=keyword>const</span> <span class=identifier>Iterator</span><span class=special>&amp;</span> <span class=identifier>y</span><span class=special>)</span><span class=keyword>const</span>
<span class=special>{</span>
<span class=keyword>return</span> <span class=identifier>comp</span><span class=special>(*</span><span class=identifier>x</span><span class=special>,*</span><span class=identifier>y</span><span class=special>);</span>
<span class=special>}</span>
<span class=keyword>private</span><span class=special>:</span>
<span class=identifier>Compare</span> <span class=identifier>comp</span><span class=special>;</span>
<span class=special>};</span>
<span class=keyword>typedef</span> <span class=identifier>std</span><span class=special>::</span><span class=identifier>set</span><span class=special>&lt;</span><span class=keyword>int</span><span class=special>&gt;</span> <span class=identifier>manual_t1</span><span class=special>;</span> <span class=comment>// equivalent to indexed_t's index #0</span>
<span class=keyword>typedef</span> <span class=identifier>std</span><span class=special>::</span><span class=identifier>multiset</span><span class=special>&lt;</span>
<span class=keyword>const</span> <span class=keyword>int</span><span class=special>*,</span>
<span class=identifier>it_compare</span><span class=special>&lt;</span>
<span class=keyword>const</span> <span class=keyword>int</span><span class=special>*,</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>greater</span><span class=special>&lt;</span><span class=keyword>int</span><span class=special>&gt;</span>
<span class=special>&gt;</span>
<span class=special>&gt;</span> <span class=identifier>manual_t2</span><span class=special>;</span> <span class=comment>// equivalent to indexed_t's index #1</span>
</pre></blockquote>
<p>
where <code>manual_t1</code> is the "base" container that holds
the actual elements, and <code>manual_t2</code> stores pointers to
elements of <code>manual_t1</code>. This scheme turns out to be quite
inefficient, though: while insertion into the data structure is simple enough:
</p>
<blockquote><pre>
<span class=identifier>manual_t1</span> <span class=identifier>c1</span><span class=special>;</span>
<span class=identifier>manual_t2</span> <span class=identifier>c2</span><span class=special>;</span>
<span class=comment>// insert the element 5</span>
<span class=identifier>manual_t1</span><span class=special>::</span><span class=identifier>iterator</span> <span class=identifier>it1</span><span class=special>=</span><span class=identifier>c1</span><span class=special>.</span><span class=identifier>insert</span><span class=special>(</span><span class=number>5</span><span class=special>).</span><span class=identifier>first</span><span class=special>;</span>
<span class=identifier>c2</span><span class=special>.</span><span class=identifier>insert</span><span class=special>(&amp;*</span><span class=identifier>it1</span><span class=special>);</span>
</pre></blockquote>
deletion, on the other hand, necessitates a logarithmic search, whereas
<code>indexed_t</code> deletes in constant time:
<blockquote><pre>
<span class=comment>// remove the element pointed to by it2</span>
<span class=identifier>manual_t2</span><span class=special>::</span><span class=identifier>iterator</span> <span class=identifier>it2</span><span class=special>=...;</span>
<span class=identifier>c1</span><span class=special>.</span><span class=identifier>erase</span><span class=special>(**</span><span class=identifier>it2</span><span class=special>);</span> <span class=comment>// watch out! performs in logarithmic time</span>
<span class=identifier>c2</span><span class=special>.</span><span class=identifier>erase</span><span class=special>(</span><span class=identifier>it2</span><span class=special>);</span>
</pre></blockquote>
<p>
The right approach consists of feeding the second container not with
raw pointers, but with elements of type <code>manual_t1::iterator</code>:
</p>
<blockquote><pre>
<span class=keyword>typedef</span> <span class=identifier>std</span><span class=special>::</span><span class=identifier>set</span><span class=special>&lt;</span><span class=keyword>int</span><span class=special>&gt;</span> <span class=identifier>manual_t1</span><span class=special>;</span> <span class=comment>// equivalent to indexed_t's index #0</span>
<span class=keyword>typedef</span> <span class=identifier>std</span><span class=special>::</span><span class=identifier>multiset</span><span class=special>&lt;</span>
<span class=identifier>manual_t1</span><span class=special>::</span><span class=identifier>iterator</span><span class=special>,</span>
<span class=identifier>it_compare</span><span class=special>&lt;</span>
<span class=identifier>manual_t1</span><span class=special>::</span><span class=identifier>iterator</span><span class=special>,</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>greater</span><span class=special>&lt;</span><span class=keyword>int</span><span class=special>&gt;</span>
<span class=special>&gt;</span>
<span class=special>&gt;</span> <span class=identifier>manual_t2</span><span class=special>;</span> <span class=comment>// equivalent to indexed_t's index #1</span>
</pre></blockquote>
<p>
Now, insertion and deletion can be performed with complexity bounds
equivalent to those of <code>indexed_t</code>:
</p>
<blockquote><pre>
<span class=identifier>manual_t1</span> <span class=identifier>c1</span><span class=special>;</span>
<span class=identifier>manual_t2</span> <span class=identifier>c2</span><span class=special>;</span>
<span class=comment>// insert the element 5</span>
<span class=identifier>manual_t1</span><span class=special>::</span><span class=identifier>iterator</span> <span class=identifier>it1</span><span class=special>=</span><span class=identifier>c1</span><span class=special>.</span><span class=identifier>insert</span><span class=special>(</span><span class=number>5</span><span class=special>).</span><span class=identifier>first</span><span class=special>;</span>
<span class=identifier>c2</span><span class=special>.</span><span class=identifier>insert</span><span class=special>(</span><span class=identifier>it1</span><span class=special>);</span>
<span class=comment>// remove the element pointed to by it2</span>
<span class=identifier>manual_t2</span><span class=special>::</span><span class=identifier>iterator</span> <span class=identifier>it2</span><span class=special>=...;</span>
<span class=identifier>c1</span><span class=special>.</span><span class=identifier>erase</span><span class=special>(*</span><span class=identifier>it2</span><span class=special>);</span> <span class=comment>// OK: constant time</span>
<span class=identifier>c2</span><span class=special>.</span><span class=identifier>erase</span><span class=special>(</span><span class=identifier>it2</span><span class=special>);</span>
</pre></blockquote>
<p>
The construction can be extended in a straightforward manner to
handle more than two indices. In what follows, we will compare
instantiations of <code>multi_index_container</code> against this sort of
manual simulations.
</p>
<h2><a name="spatial_efficiency">Spatial efficiency</a></h2>
<p>
The gain in space consumption of <code>multi_index_container</code> with
respect to its manual simulations is amenable to a very simple
theoretical analysis. For simplicity, we will ignore alignment
issues (which in general play in favor of <code>multi_index_container</code>.)
</p>
<p>
Nodes of a <code>multi_index_container</code> with <i>N</i> indices hold the value
of the element plus <i>N</i> headers containing linking information for
each index. Thus the node size is
</p>
<blockquote>
<i>S<sub>I</sub></i> = <i>e</i> + <i>h</i><sub>0</sub> + <20><><EFBFBD> +
<i>h</i><sub><i>N</i>-1</sub>, where<br>
<i>e</i> = size of the element,<br>
<i>h</i><sub><i>i</i></sub> = size of the <i>i</i>-th header.
</blockquote>
<p>
On the other hand, the manual simulation allocates <i>N</i> nodes per
element, the first holding the elements themselves and the rest
storing iterators to the "base" container. In practice, an iterator
merely holds a raw pointer to the node it is associated to, so its size
is independent of the type of the elements. Summing all contributions,
the space allocated per element in a manual simulation is
</p>
<blockquote>
<i>S<sub>M</sub></i> = (<i>e</i> + <i>h</i><sub>0</sub>) +
(<i>p</i> + <i>h</i><sub>1</sub>) + <20><><EFBFBD> +
(<i>p</i> + <i>h</i><sub><i>N</i>-1</sub>) =
<i>S<sub>I</sub></i> + (<i>N</i>-1)<i>p</i>, where<br>
<i>p</i> = size of a pointer.<br>
</blockquote>
<p>
The relative amount of memory taken up by <code>multi_index_container</code>
with respect to its manual simulation is just
<i>S<sub>I</sub></i>&nbsp;/&nbsp;<i>S<sub>M</sub></i>, which can be expressed
then as:
</p>
<blockquote>
<i>S<sub>I</sub></i>&nbsp;/&nbsp;<i>S<sub>M</sub></i> =
<i>S<sub>I</sub></i>&nbsp;/&nbsp;(<i>S<sub>I</sub></i> + (<i>N</i>-1)<i>p</i>).
</blockquote>
<p>
The formula shows that <code>multi_index_container</code> is more efficient
with regard to memory consumption as the number of indices grow. An implicit
assumption has been made that headers of <code>multi_index_container</code>
index nodes are the same size that their analogues in STL containers; but there
is a particular case in which this is often not the case: ordered indices use a
<a href="tutorial/indices.html#ordered_node_compression">spatial optimization
technique</a> which is not present in many implementations of
<code>std::set</code>, giving an additional advantage to
<code>multi_index_container</code>s of one system word per ordered index.
Taking this fact into account, the former formula can be adjusted to:
</p>
<blockquote>
<i>S<sub>I</sub></i>&nbsp;/&nbsp;<i>S<sub>M</sub></i> =
<i>S<sub>I</sub></i>&nbsp;/&nbsp;(<i>S<sub>I</sub></i> + (<i>N</i>-1)<i>p</i> + <i>Ow</i>),
</blockquote>
<p>
where <i>O</i> is the number of ordered indices of the container, and <i>w</i>
is the system word size (typically 4 bytes on 32-bit architectures.)
</p>
<p>
These considerations have overlooked an aspect of the greatest practical
importance: the fact that <code>multi_index_container</code> allocates a single
node per element, compared to the many nodes of different sizes
built by manual simulations, diminishes memory fragmentation, which
can show up in more usable memory available and better performance.
</p>
<h2><a name="time_efficiency">Time efficiency</a></h2>
<p>
From the point of view of computational complexity (i.e. big-O
characterization), <code>multi_index_container</code> and its corresponding manual
simulations are equivalent: inserting an element into
a <code>multi_index_container</code> reduces to a simple combination of
elementary insertion operations on each of the indices, and
similarly for deletion. Hence, the most we can expect is a reduction
(or increase) of execution time by a roughly constant factor. As we
will see later, the reduction can be very significative for
<code>multi_index_container</code>s with two or more indices.
</p>
<p>In the special case of <code>multi_index_container</code>s with only one index,
resulting performance will roughly match that of the STL equivalent containers:
tests show that there is at most a negligible degradation with respect to STL,
and even in some cases a small improvement.
</p>
<h2><a name="tests">Performance tests</a></h2>
<p>
See <a href="../perf/test_perf.cpp">source code</a> used for measurements.
<p>
In order to assess the efficiency of <code>multi_index_container</code>, the following
basic algorithm
</p>
<blockquote><pre>
<span class=identifier>multi_index_container</span><span class=special>&lt;...&gt;</span> <span class=identifier>c</span><span class=special>;</span>
<span class=keyword>for</span><span class=special>(</span><span class=keyword>int</span> <span class=identifier>i</span><span class=special>=</span><span class=number>0</span><span class=special>;</span><span class=identifier>i</span><span class=special>&lt;</span><span class=identifier>n</span><span class=special>;++</span><span class=identifier>i</span><span class=special>)</span><span class=identifier>c</span><span class=special>.</span><span class=identifier>insert</span><span class=special>(</span><span class=identifier>i</span><span class=special>);</span>
<span class=keyword>for</span><span class=special>(</span><span class=identifier>iterator</span> <span class=identifier>it</span><span class=special>=</span><span class=identifier>c</span><span class=special>.</span><span class=identifier>begin</span><span class=special>();</span><span class=identifier>it</span><span class=special>!=</span><span class=identifier>c</span><span class=special>.</span><span class=identifier>end</span><span class=special>();)</span><span class=identifier>c</span><span class=special>.</span><span class=identifier>erase</span><span class=special>(</span><span class=identifier>it</span><span class=special>++);</span>
</pre></blockquote>
<p>
has been measured for different instantiations of <code>multi_index_container</code>
at values of <i>n</i> 1,000, 10,000 and 100,000,
and its execution time compared with that of the equivalent algorithm
for the corresponding manual simulation of the data structure based on
STL containers. The table below describes the test environments used.
</p>
<p align="center">
<table cellspacing="0" cellpadding="5">
<caption><b>Tests environments.</b></caption>
<tr>
<th>Compiler</th>
<th>Settings</th>
<th>OS and CPU</th>
</tr>
<tr>
<td>GCC 3.4.5 (mingw special)</td>
<td><code>-O3</code></td>
<td>Windows 2000 Pro on P4 1.5 GHz, 256 MB RAM</td>
</tr>
<tr class="odd_tr">
<td>Intel C++ 7.1</td>
<td>default release settings</td>
<td>Windows 2000 Pro on P4 1.5 GHz, 256 MB RAM</td>
</tr>
<tr>
<td>Microsoft Visual C++ 8.0</td>
<td>default release settings, <code>_SECURE_SCL=0</code></td>
<td>Windows XP on P4 Xeon 3.2 GHz, 1 GB RAM</td>
</tr>
</table>
</p>
<p>
The relative memory consumption (i.e. the amount of memory allocated
by a <code>multi_index_container</code> with respect to its manual simulation)
is determined by dividing the size of a <code>multi_index_container</code> node
by the sum of node sizes of all the containers integrating the
simulating data structure.
</p>
<h3><a name="test_1r">Results for 1 ordered index</a></h3>
<p>
The following instantiation of <code>multi_index_container</code> was tested:
</p>
<blockquote><pre>
<span class=identifier>multi_index_container</span><span class=special>&lt;</span>
<span class=keyword>int</span><span class=special>,</span>
<span class=identifier>indexed_by</span><span class=special>&lt;</span>
<span class=identifier>ordered_unique</span><span class=special>&lt;</span><span class=identifier>identity</span><span class=special>&lt;</span><span class=keyword>int</span><span class=special>&gt;</span> <span class=special>&gt;</span>
<span class=special>&gt;</span>
<span class=special>&gt;</span>
</pre></blockquote>
<p>
which is functionally equivalent to <code>std::set&lt;int></code>.
</p>
<h4><a name="memory_1r">Memory consumption</a></h4>
<p align="center">
<table cellspacing="0">
<tr>
<th width="33%">GCC 3.4.5</th>
<th width="33%">ICC 7.1</th>
<th width="33%">MSVC 8.0</th>
</tr>
<tr>
<td align="center">80%</td>
<td align="center">80%</td>
<td align="center">80%</td>
</tr>
</table>
<b>Table 1: Relative memory consumption of <code>multi_index_container</code> with 1
ordered index.</b>
</p>
<p>
The reduction in memory usage is accounted for by the optimization technique implemented
in Boost.MultiIndex ordered indices, as <a href="#spatial_efficiency">explained above</a>.
</p>
<h4><a name="time_1r">Execution time</a></h4>
<p align="center">
<img src="perf_1o.png" alt="performance of multi_index_container with 1 ordered index"
width="556" height="372"><br>
<b>Fig. 1: Performance of <code>multi_index_container</code> with 1 ordered index.</b>
</p>
<p>
Somewhat surprisingly, <code>multi_index_container</code> performs slightly
better than <code>std::set</code>. A very likely explanation for this behavior
is that the lower memory consumption of <code>multi_index_container</code>
results in a higher processor cache hit rate.
The improvement is smallest for GCC, presumably because the worse quality of
this compiler's optimizer masks the cache-related benefits.
</p>
<h3><a name="test_1s">Results for 1 sequenced index</a></h3>
<p>
The following instantiation of <code>multi_index_container</code> was tested:
</p>
<blockquote><pre>
<span class=identifier>multi_index_container</span><span class=special>&lt;</span>
<span class=keyword>int</span><span class=special>,</span>
<span class=identifier>indexed_by</span><span class=special>&lt;</span>
<span class=identifier>sequenced</span><span class=special>&lt;&gt;</span>
<span class=special>&gt;</span>
<span class=special>&gt;</span>
</pre></blockquote>
<p>
which is functionally equivalent to <code>std::list&lt;int></code>.
</p>
<h4><a name="memory_1s">Memory consumption</a></h4>
<p align="center">
<table cellspacing="0">
<tr>
<th width="33%">GCC 3.4.5</th>
<th width="33%">ICC 7.1</th>
<th width="33%">MSVC 8.0</th>
</tr>
<tr>
<td align="center">100%</td>
<td align="center">100%</td>
<td align="center">100%</td>
</tr>
</table>
<b>Table 2: Relative memory consumption of <code>multi_index_container</code> with 1
sequenced index.</b>
</p>
<p>
The figures confirm that in this case <code>multi_index_container</code> nodes are the
same size than those of its <code>std::list</code> counterpart.
</p>
<h4><a name="time_1s">Execution time</a></h4>
<p align="center">
<img src="perf_1s.png" alt="performance of multi_index_container with 1 sequenced index"
width="556" height="372"><br>
<b>Fig. 2: Performance of <code>multi_index_container</code> with 1 sequenced index.</b>
</p>
<p>
<code>multi_index_container</code> does not attain the performance
of its STL counterpart, although the figures are close. Again, the worst results
are those of GCC, with a degradation of up to 7%, while ICC and MSVC do not
exceed a mere 5%.
</p>
<h3><a name="test_2r">Results for 2 ordered indices</a></h3>
<p>
The following instantiation of <code>multi_index_container</code> was tested:
</p>
<blockquote><pre>
<span class=identifier>multi_index_container</span><span class=special>&lt;</span>
<span class=keyword>int</span><span class=special>,</span>
<span class=identifier>indexed_by</span><span class=special>&lt;</span>
<span class=identifier>ordered_unique</span><span class=special>&lt;</span><span class=identifier>identity</span><span class=special>&lt;</span><span class=keyword>int</span><span class=special>&gt;</span> <span class=special>&gt;,</span>
<span class=identifier>ordered_non_unique</span><span class=special>&lt;</span><span class=identifier>identity</span><span class=special>&lt;</span><span class=keyword>int</span><span class=special>&gt;</span> <span class=special>&gt;</span>
<span class=special>&gt;</span>
<span class=special>&gt;</span>
</pre></blockquote>
<h4><a name="memory_2r">Memory consumption</a></h4>
<p align="center">
<table cellspacing="0">
<tr>
<th width="33%">GCC 3.4.5</th>
<th width="33%">ICC 7.1</th>
<th width="33%">MSVC 8.0</th>
</tr>
<tr>
<td align="center">70%</td>
<td align="center">70%</td>
<td align="center">70%</td>
</tr>
</table>
<b>Table 3: Relative memory consumption of <code>multi_index_container</code> with 2
ordered indices.</b>
</p>
<p>
These results coincide with the theoretical formula for
<i>S<sub>I</sub></i> = 28, <i>N</i> = <i>O</i> = 2 and <i>p</i> = <i>w</i> = 4.
</p>
<h4><a name="time_2r">Execution time</a></h4>
<p align="center">
<img src="perf_2o.png" alt="performance of multi_index_container with 2 ordered indices"
width="556" height="372"><br>
<b>Fig. 3: Performance of <code>multi_index_container</code> with 2 ordered indices.</b>
</p>
<p>
The experimental results confirm our hypothesis that <code>multi_index_container</code>
provides an improvement on execution time by an approximately constant factor,
which in this case lies around 60%. There is no obvious explanation for the
increased advantage of <code>multi_index_container</code> in MSVC for
<i>n</i>=10<sup>5</sup>.
</p>
<h3><a name="test_1r1s">Results for 1 ordered index + 1 sequenced index</a></h3>
<p>
The following instantiation of <code>multi_index_container</code> was tested:
</p>
<blockquote><pre>
<span class=identifier>multi_index_container</span><span class=special>&lt;</span>
<span class=keyword>int</span><span class=special>,</span>
<span class=identifier>indexed_by</span><span class=special>&lt;</span>
<span class=identifier>ordered_unique</span><span class=special>&lt;</span><span class=identifier>identity</span><span class=special>&lt;</span><span class=keyword>int</span><span class=special>&gt;</span> <span class=special>&gt;,</span>
<span class=identifier>sequenced</span><span class=special>&lt;&gt;</span>
<span class=special>&gt;</span>
<span class=special>&gt;</span>
</pre></blockquote>
<h4><a name="memory_1r1s">Memory consumption</a></h4>
<p align="center">
<table cellspacing="0">
<tr>
<th width="33%">GCC 3.4.5</th>
<th width="33%">ICC 7.1</th>
<th width="33%">MSVC 8.0</th>
</tr>
<tr>
<td align="center">75%</td>
<td align="center">75%</td>
<td align="center">75%</td>
</tr>
</table>
<b>Table 4: Relative memory consumption of <code>multi_index_container</code> with 1
ordered index + 1 sequenced index.</b>
</p>
<p>
These results coincide with the theoretical formula for
<i>S<sub>I</sub></i> = 24, <i>N</i> = 2, <i>O</i> = 1 and <i>p</i> = <i>w</i> = 4.
</p>
<h4><a name="time_1r1s">Execution time</a></h4>
<p align="center">
<img src="perf_1o1s.png"
alt="performance of multi_index_container with 1 ordered index + 1 sequenced index"
width="556" height="372"><br>
<b>Fig. 4: Performance of <code>multi_index_container</code> with 1 ordered index
+ 1 sequenced index.</b>
</p>
<p>
For <i>n</i>=10<sup>3</sup> and <i>n</i>=10<sup>4</sup>, the results
are in agreement with our theoretical analysis, showing a constant factor
improvement of 50-65% with respect to the STL-based manual simulation.
Curiously enough, this speedup gets even higher when
<i>n</i>=10<sup>5</sup> for two of the compilers, namely GCC and ICC.
In order to rule out spurious results, the tests
have been run many times, yielding similar outcomes. Both test environments
are deployed on the same machine, which points to some OS-related reason for
this phenomenon.
</p>
<h3><a name="test_3r">Results for 3 ordered indices</a></h3>
<p>
The following instantiation of <code>multi_index_container</code> was tested:
</p>
<blockquote><pre>
<span class=identifier>multi_index_container</span><span class=special>&lt;</span>
<span class=keyword>int</span><span class=special>,</span>
<span class=identifier>indexed_by</span><span class=special>&lt;</span>
<span class=identifier>ordered_unique</span><span class=special>&lt;</span><span class=identifier>identity</span><span class=special>&lt;</span><span class=keyword>int</span><span class=special>&gt;</span> <span class=special>&gt;,</span>
<span class=identifier>ordered_non_unique</span><span class=special>&lt;</span><span class=identifier>identity</span><span class=special>&lt;</span><span class=keyword>int</span><span class=special>&gt;</span> <span class=special>&gt;,</span>
<span class=identifier>ordered_non_unique</span><span class=special>&lt;</span><span class=identifier>identity</span><span class=special>&lt;</span><span class=keyword>int</span><span class=special>&gt;</span> <span class=special>&gt;</span>
<span class=special>&gt;</span>
<span class=special>&gt;</span>
</pre></blockquote>
<h4><a name="memory_3r">Memory consumption</a></h4>
<p align="center">
<table cellspacing="0">
<tr>
<th width="33%">GCC 3.4.5</th>
<th width="33%">ICC 7.1</th>
<th width="33%">MSVC 8.0</th>
</tr>
<tr>
<td align="center">66.7%</td>
<td align="center">66.7%</td>
<td align="center">66.7%</td>
</tr>
</table>
<b>Table 5: Relative memory consumption of <code>multi_index_container</code> with 3
ordered indices.</b>
</p>
<p>
These results coincide with the theoretical formula for
<i>S<sub>I</sub></i> = 40, <i>N</i> = <i>O</i> = 3 and <i>p</i> = <i>w</i> = 4.
</p>
<h4><a name="time_3r">Execution time</a></h4>
<p align="center">
<img src="perf_3o.png" alt="performance of multi_index_container with 3 ordered indices"
width="556" height="372"><br>
<b>Fig. 5: Performance of <code>multi_index_container</code> with 3 ordered indices.</b>
</p>
<p>
Execution time for this case is between 45% and 55% lower than achieved with
an STL-based manual simulation of the same data structure.
</p>
<h3><a name="test_2r1s">Results for 2 ordered indices + 1 sequenced index</a></h3>
<p>
The following instantiation of <code>multi_index_container</code> was tested:
</p>
<blockquote><pre>
<span class=identifier>multi_index_container</span><span class=special>&lt;</span>
<span class=keyword>int</span><span class=special>,</span>
<span class=identifier>indexed_by</span><span class=special>&lt;</span>
<span class=identifier>ordered_unique</span><span class=special>&lt;</span><span class=identifier>identity</span><span class=special>&lt;</span><span class=keyword>int</span><span class=special>&gt;</span> <span class=special>&gt;,</span>
<span class=identifier>ordered_non_unique</span><span class=special>&lt;</span><span class=identifier>identity</span><span class=special>&lt;</span><span class=keyword>int</span><span class=special>&gt;</span> <span class=special>&gt;,</span>
<span class=identifier>sequenced</span><span class=special>&lt;&gt;</span>
<span class=special>&gt;</span>
<span class=special>&gt;</span>
</pre></blockquote>
<h4><a name="memory_2r1s">Memory consumption</a></h4>
<p align="center">
<table cellspacing="0">
<tr>
<th width="33%">GCC 3.4.5</th>
<th width="33%">ICC 7.1</th>
<th width="33%">MSVC 8.0</th>
</tr>
<tr>
<td align="center">69.2%</td>
<td align="center">69.2%</td>
<td align="center">69.2%</td>
</tr>
</table>
<b>Table 6: Relative memory consumption of <code>multi_index_container</code> with 2
ordered indices + 1 sequenced index.</b>
</p>
<p>
These results coincide with the theoretical formula for
<i>S<sub>I</sub></i> = 36, <i>N</i> = 3, <i>O</i> = 2 and <i>p</i> = <i>w</i> = 4.
</p>
<h4><a name="time_2r1s">Execution time</a></h4>
<p align="center">
<img src="perf_2o1s.png"
alt="performance of multi_index_container with 2 ordered indices + 1 sequenced index"
width="556" height="372"><br>
<b>Fig. 6: Performance of <code>multi_index_container</code> with 2 ordered indices
+ 1 sequenced index.</b>
</p>
<p>
In accordance to the expectations, execution time is improved by a fairly constant
factor, which ranges from 45% to 55%.
</p>
<h2><a name="conclusions">Conclusions</a></h2>
<p>
We have shown that <code>multi_index_container</code> outperforms, both in space and
time efficiency, equivalent data structures obtained from the manual
combination of STL containers. This improvement gets larger when the number
of indices increase.
</p>
<p>
In the special case of replacing standard containers with single-indexed
<code>multi_index_container</code>s, the performance of Boost.MultiIndex
is comparable with that of the tested STL implementations, and can even yield
some improvements both in space consumption and execution time.
</p>
<hr>
<div class="prev_link"><a href="compiler_specifics.html"><img src="prev.gif" alt="compiler specifics" border="0"><br>
Compiler specifics
</a></div>
<div class="up_link"><a href="index.html"><img src="up.gif" alt="index" border="0"><br>
Index
</a></div>
<div class="next_link"><a href="examples.html"><img src="next.gif" alt="examples" border="0"><br>
Examples
</a></div><br clear="all" style="clear: all;">
<br>
<p>Revised November 24th 2015</p>
<p>&copy; Copyright 2003-2015 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz.
Distributed under the Boost Software
License, Version 1.0. (See accompanying file <a href="../../../LICENSE_1_0.txt">
LICENSE_1_0.txt</a> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">
http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 852 B

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,148 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0.1 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Boost.MultiIndex Documentation - Reference</title>
<link rel="stylesheet" href="../style.css" type="text/css">
<link rel="start" href="../index.html">
<link rel="prev" href="../tutorial/techniques.html">
<link rel="up" href="../index.html">
<link rel="next" href="multi_index_container.html">
</head>
<body>
<h1><img src="../../../../boost.png" alt="boost.png (6897 bytes)" align=
"middle" width="277" height="86">Boost.MultiIndex Reference</h1>
<div class="prev_link"><a href="../tutorial/techniques.html"><img src="../prev.gif" alt="techniques" border="0"><br>
Techniques
</a></div>
<div class="up_link"><a href="../index.html"><img src="../up.gif" alt="index" border="0"><br>
Index
</a></div>
<div class="next_link"><a href="multi_index_container.html"><img src="../next.gif" alt="multi_index_container reference" border="0"><br>
<code>multi_index_container</code> reference
</a></div><br clear="all" style="clear: all;">
<hr>
<h2>Contents</h2>
<ul>
<li><a href="#header_dependencies">Header dependencies</a></li>
<li><a href="multi_index_container.html">Class template <code>multi_index_container</code></a></li>
<li><a href="indices.html">Index reference</a></li>
<li><a href="ord_indices.html">Ordered indices</a></li>
<li><a href="rnk_indices.html">Ranked indices</a></li>
<li><a href="hash_indices.html">Hashed indices</a></li>
<li><a href="seq_indices.html">Sequenced indices</a></li>
<li><a href="rnd_indices.html">Random access indices</a></li>
<li><a href="key_extraction.html">Key Extraction</a></li>
</ul>
<h2><a name="header_dependencies">Header dependencies</a></h2>
<p>
The following dependencies among headers of Boost.MultiIndex hold:
<ul>
<li><a href="multi_index_container.html#synopsis"><code>"boost/multi_index_container.hpp"</code></a>
includes
<ul>
<li><a href="indices.html#indexed_by_synopsis">
<code>"boost/multi_index/indexed_by.hpp"</code></a>.</li>
</ul>
</li>
<li><a href="ord_indices.html#synopsis">
<code>"boost/multi_index/ordered_index.hpp"</code></a> includes
<ul>
<li><a href="indices.html#tag_synopsis">
<code>"boost/multi_index/tag.hpp"</code></a>.</li>
</ul>
</li>
<li><a href="rnk_indices.html#synopsis">
<code>"boost/multi_index/ranked_index.hpp"</code></a> includes
<ul>
<li><a href="indices.html#tag_synopsis">
<code>"boost/multi_index/tag.hpp"</code></a>.</li>
</ul>
</li>
<li><a href="hash_indices.html#synopsis">
<code>"boost/multi_index/hashed_index.hpp"</code></a> includes
<ul>
<li><a href="indices.html#tag_synopsis">
<code>"boost/multi_index/tag.hpp"</code></a>.</li>
</ul>
</li>
<li><a href="seq_indices.html#synopsis">
<code>"boost/multi_index/sequenced_index.hpp"</code></a> includes
<ul>
<li><a href="indices.html#tag_synopsis">
<code>"boost/multi_index/tag.hpp"</code></a>.</li>
</ul>
</li>
<li><a href="rnd_indices.html#synopsis">
<code>"boost/multi_index/random_access_index.hpp"</code></a> includes
<ul>
<li><a href="indices.html#tag_synopsis">
<code>"boost/multi_index/tag.hpp"</code></a>.</li>
</ul>
</li>
<li><a href="key_extraction.html#synopsis"><code>"boost/multi_index/key_extractors.hpp"</code></a>
includes
<ul>
<li><a href="key_extraction.html#identity_synopsis">
<code>"boost/multi_index/identity.hpp"</code></a>,</li>
<li><a href="key_extraction.html#member_synopsis">
<code>"boost/multi_index/member.hpp"</code></a>,</li>
<li><a href="key_extraction.html#mem_fun_synopsis">
<code>"boost/multi_index/mem_fun.hpp"</code></a>,</li>
<li><a href="key_extraction.html#global_fun_synopsis">
<code>"boost/multi_index/global_fun.hpp"</code></a> and</li>
<li><a href="key_extraction.html#composite_key_synopsis">
<code>"boost/multi_index/composite_key.hpp"</code></a>.</li>
</ul>
</li>
</ul>
So, a program using Boost.MultiIndex must include
<a href="multi_index_container.html#synopsis">
<code>"boost/multi_index_container.hpp"</code></a>,
the headers defining the index types to be used and possibly one or more key
extraction headers for key-based indices. Note that all the key extractors
provided by Boost.MultiIndex are automatically included with
<a href="key_extraction.html#synopsis">
<code>"boost/multi_index/key_extractors.hpp"</code></a>.
</p>
<p>
In order to use the serialization capabilities of Boost.MultiIndex,
the appropriate Boost.Serialization library module must be linked. Other
than that, Boost.MultiIndex is a header-only library, requiring no additional
object modules.
</p>
<hr>
<div class="prev_link"><a href="../tutorial/techniques.html"><img src="../prev.gif" alt="techniques" border="0"><br>
Techniques
</a></div>
<div class="up_link"><a href="../index.html"><img src="../up.gif" alt="index" border="0"><br>
Index
</a></div>
<div class="next_link"><a href="multi_index_container.html"><img src="../next.gif" alt="multi_index_container reference" border="0"><br>
<code>multi_index_container</code> reference
</a></div><br clear="all" style="clear: all;">
<br>
<p>Revised November 24th 2015</p>
<p>&copy; Copyright 2003-2015 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz.
Distributed under the Boost Software
License, Version 1.0. (See accompanying file <a href="../../../../LICENSE_1_0.txt">
LICENSE_1_0.txt</a> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">
http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</body>
</html>

View File

@@ -0,0 +1,399 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0.1 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Boost.MultiIndex Documentation - Index reference</title>
<link rel="stylesheet" href="../style.css" type="text/css">
<link rel="start" href="../index.html">
<link rel="prev" href="multi_index_container.html">
<link rel="up" href="index.html">
<link rel="next" href="ord_indices.html">
</head>
<body>
<h1><img src="../../../../boost.png" alt="boost.png (6897 bytes)" align=
"middle" width="277" height="86">Boost.MultiIndex Index reference</h1>
<div class="prev_link"><a href="multi_index_container.html"><img src="../prev.gif" alt="multi_index_container reference" border="0"><br>
<code>multi_index_container</code> reference
</a></div>
<div class="up_link"><a href="index.html"><img src="../up.gif" alt="Boost.MultiIndex reference" border="0"><br>
Boost.MultiIndex reference
</a></div>
<div class="next_link"><a href="ord_indices.html"><img src="../next.gif" alt="ordered indices" border="0"><br>
Ordered indices
</a></div><br clear="all" style="clear: all;">
<hr>
<h2>Contents</h2>
<ul>
<li><a href="#index_concepts">Index concepts</a></li>
<li><a href="#complexity_signature">Complexity signature</a></li>
<li><a href="#index_specification">Index specification</a></li>
<li><a href="#indexed_by_synopsis">Header
<code>"boost/multi_index/indexed_by.hpp"</code> synopsis</a>
<ul>
<li><a href="#indexed_by">Class template <code>indexed_by</code></a></li>
</ul>
</li>
<li><a href="#tags">Tags</a></li>
<li><a href="#tag_synopsis">Header
<code>"boost/multi_index/tag.hpp"</code> synopsis</a>
<ul>
<li><a href="#tag">Class template <code>tag</code></a></li>
</ul>
</li>
<li><a href="#index_catalog">Indices provided by Boost.MultiIndex</a>
<ul>
<li><a href="#key_based_indices">Key-based indices</a></li>
<li><a href="#other_indices">Other types</a></li>
</ul>
</li>
<li><a href="#views">Index views</a></li>
</ul>
<h2><a name="index_concepts">Index concepts</a></h2>
<p>
<code>multi_index_container</code> 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,
<a href="ord_indices.html">ordered indices</a>
provide a set-like interface to the elements, whereas
<a href="seq_indices.html">sequenced indices</a> mimic the functionality
of <code>std::list</code>.
</p>
<p>
Indices are not isolated objects, and so cannot be constructed on their
own. Rather they are embedded into a <code>multi_index_container</code> as specified by
means of an <a href="#index_specification">index specifier</a>. The name of
the index class implementation proper is never directly exposed to the user, who
has only access to the associated index specifier.
</p>
<p>
Insertion and erasing of elements are always performed through the
appropriate interface of some index of the <code>multi_index_container</code>;
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:
<ul>
<li>Copying,</li>
<li>insertion of an element,</li>
<li>hinted insertion, where a preexisting element is suggested in
order to improve the efficiency of the operation,</li>
<li>deletion of an element,</li>
<li>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,</li>
<li>modification of an element, and its subsequent
rearrangement/banning by the various indices.
</ul>
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 <code>multi_index_container</code> 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 <code>std::list</code>.
</p>
<p>
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 <code>push_back</code> and <code>push_front</code>
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.
</p>
<h2><a name="complexity_signature">Complexity signature</a></h2>
<p>
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 <code>multi_index_container</code>, not just
the currently used index.
</p>
<p>
In order to establish complexity estimates, an index is characterized
by its <i>complexity signature</i>, consisting of the following
associated functions on the number of elements:
<ul>
<li><code>c(n)</code>: copying,
<li><code>i(n)</code>: insertion,
<li><code>h(n)</code>: hinted insertion,
<li><code>d(n)</code>: deletion,
<li><code>r(n)</code>: replacement,
<li><code>m(n)</code>: modifying.
</ul>
</p>
Each function yields the complexity estimate of the contribution of the index
to the corresponding global primitive. Let us consider
an instantiation of <code>multi_index_container</code>
with <code>N</code> indices labelled <code>0</code>,...,<code>N-1</code>
whose complexity signatures are
(<code>c<sub>i</sub></code>,<code>i<sub>i</sub></code>,<code>h<sub>i</sub></code>,<code>d<sub>i</sub></code>,<code>r<sub>i</sub></code>,<code>m<sub>i</sub></code>);
the insertion of an element in such a container is then of complexity
<code>O(i<sub>0</sub>(n)+<2B><><EFBFBD>+i<sub>N-1</sub>(n))</code> where <code>n</code>
is the number of elements. To abbreviate notation, we adopt the
following definitions:
<ul>
<li><code>C(n)=c<sub>0</sub>(n)+<2B><><EFBFBD>+c<sub>N-1</sub>(n)</code>,</li>
<li><code>I(n)=i<sub>0</sub>(n)+<2B><><EFBFBD>+i<sub>N-1</sub>(n)</code>,</li>
<li><code>H(n)=h<sub>0</sub>(n)+<2B><><EFBFBD>+h<sub>N-1</sub>(n)</code>,</li>
<li><code>D(n)=d<sub>0</sub>(n)+<2B><><EFBFBD>+d<sub>N-1</sub>(n)</code>,</li>
<li><code>R(n)=r<sub>0</sub>(n)+<2B><><EFBFBD>+r<sub>N-1</sub>(n)</code>,</li>
<li><code>M(n)=m<sub>0</sub>(n)+<2B><><EFBFBD>+m<sub>N-1</sub>(n)</code>.</li>
</ul>
For instance, consider a <code>multi_index_container</code> with two ordered indices,
for which <code>i(n)=log(n)</code>, and a sequenced index with <code>i(n)=1</code>
(constant time insertion). Insertion of an element into this <code>multi_index_container</code>
is then of complexity
<blockquote>
<code>O(I(n))=O(2*log(n)+1)=O(log(n))</code>.
</blockquote>
</p>
<h2><a name="index_specification">Index specification</a></h2>
<p>
Index specifiers are passed as instantiation arguments to
<code>multi_index_container</code> 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
<ul>
<li><a href="ord_indices.html#unique_non_unique"><code>ordered_unique</code> and
<code>ordered_non_unique</code></a> for
<a href="ord_indices.html">ordered indices</a>,</li>
<li><a href="rnk_indices.html#unique_non_unique"><code>ranked_unique</code> and
<code>ranked_non_unique</code></a> for
<a href="rnk_indices.html">ranked indices</a>,</li>
<li><a href="hash_indices.html#unique_non_unique"><code>hashed_unique</code> and
<code>hashed_non_unique</code></a> for
<a href="hash_indices.html">hashed indices</a>,</li>
<li><a href="seq_indices.html#sequenced"><code>sequenced</code></a> for
<a href="seq_indices.html">sequenced indices</a>,</li>
<li>and <a href="rnd_indices.html#random_access"><code>random_access</code></a> for
<a href="rnd_indices.html">random access indices</a>.</li>
</ul>
</p>
<h2>
<a name="indexed_by_synopsis">Header
<a href="../../../../boost/multi_index/indexed_by.hpp">
<code>"boost/multi_index/indexed_by.hpp"</code></a> synopsis</a></h2>
<blockquote><pre>
<span class=keyword>namespace</span> <span class=identifier>boost</span><span class=special>{</span>
<span class=keyword>namespace</span> <span class=identifier>multi_index</span><span class=special>{</span>
<span class=keyword>template</span><span class=special>&lt;</span><span class=keyword>typename</span> <span class=identifier>T0</span><span class=special>,...,</span><span class=keyword>typename</span> <span class=identifier>Tn</span><span class=special>&gt;</span>
<span class=keyword>struct</span> <span class=identifier>indexed_by</span><span class=special>;</span>
<span class=special>}</span> <span class=comment>// namespace boost::multi_index</span>
<span class=special>}</span> <span class=comment>// namespace boost</span>
</pre></blockquote>
<h3><a name="indexed_by">Class template <code>indexed_by</code></a></h3>
<p>
<code>indexed_by</code> is a model of
<a href="../../../../libs/mpl/doc/refmanual/random-access-sequence.html">
<code>MPL Random Access Sequence</code></a> and
<a href="../../../../libs/mpl/doc/refmanual/extensible-sequence.html">
<code>MPL Extensible Sequence</code></a> meant to be used to specify a
compile-time list of indices as the <code>IndexSpecifierList</code> of
<code>multi_index_container</code>.
</p>
<blockquote><pre>
<span class=keyword>template</span><span class=special>&lt;</span><span class=keyword>typename</span> <span class=identifier>T0</span><span class=special>,...,</span><span class=keyword>typename</span> <span class=identifier>Tn</span><span class=special>&gt;</span>
<span class=keyword>struct</span> <span class=identifier>indexed_by</span><span class=special>;</span>
</pre></blockquote>
<p>
Each user-provided element of <code>indexed_list</code> must be an index
specifier. At least an element must be provided. The maximum number of elements
of an <code>indexed_by</code> sequence is implementation defined.
</p>
<h2><a name="tags">Tags</a></h2>
<p>
Tags are just conventional types used as mnemonics for indices of an
<code>multi_index_container</code>, as for instance in member function <code>get</code>.
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 <a href="#tag"><code>tag</code></a>.
</p>
<h2>
<a name="tag_synopsis">Header
<a href="../../../../boost/multi_index/tag.hpp">
<code>"boost/multi_index/tag.hpp"</code></a> synopsis</a></h2>
<blockquote><pre>
<span class=keyword>namespace</span> <span class=identifier>boost</span><span class=special>{</span>
<span class=keyword>namespace</span> <span class=identifier>multi_index</span><span class=special>{</span>
<span class=keyword>template</span><span class=special>&lt;</span><span class=keyword>typename</span> <span class=identifier>T0</span><span class=special>,...,</span><span class=keyword>typename</span> <span class=identifier>Tn</span><span class=special>&gt;</span>
<span class=keyword>struct</span> <span class=identifier>tag</span><span class=special>;</span>
<span class=special>}</span> <span class=comment>// namespace boost::multi_index</span>
<span class=special>}</span> <span class=comment>// namespace boost</span>
</pre></blockquote>
<h3><a name="tag">Class template <code>tag</code></a></h3>
<p>
<code>tag</code> is a typelist construct used to specify a compile-time
sequence of tags to be assigned to an index in instantiation time.
</p>
<blockquote><pre>
<span class=keyword>template</span><span class=special>&lt;</span><span class=keyword>typename</span> <span class=identifier>T0</span><span class=special>,...,</span><span class=keyword>typename</span> <span class=identifier>Tn</span><span class=special>&gt;</span>
<span class=keyword>struct</span> <span class=identifier>tag</span>
<span class=special>{</span>
<span class=keyword>typedef</span> <b>implementation defined</b> <span class=identifier>type</span><span class=special>;</span>
<span class=special>};</span>
</pre></blockquote>
<p>
Elements of <code>tag</code> 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 <code>tag</code> instantiation is
implementation defined.
The nested
<code>type</code> is a model of
<a href="../../../../libs/mpl/doc/refmanual/random-access-sequence.html">
<code>MPL Random Access Sequence</code></a> and
<a href="../../../../libs/mpl/doc/refmanual/extensible-sequence.html">
<code>MPL Extensible Sequence</code></a> containing the types <code>T0</code>, ... ,
<code>Tn</code> in the same order as specified.
</p>
<h2><a name="index_catalog">Indices provided by Boost.MultiIndex</a></h2>
<h3><a name="key_based_indices">Key-based indices</a></h3>
<p>
Indices of this type are organized around <i>keys</i> obtained from the
elements, as described in the <a href="key_extraction.html">key extraction
reference</a>.
<ul>
<li><a href="ord_indices.html">Ordered indices</a> sort the elements
on the key and provide fast lookup capabilites.</li>
<li><a href="rnk_indices.html">Ranked indices</a> are a variation of
ordered indices providing extra operations based on
<i>rank</i>, the numerical position of an element
in the sequence.</li>
<li><a href="hash_indices.html">Hashed indices</a> offer high
efficiency access through hashing techniques.</li>
</ul>
</p>
<h3><a name="other_indices">Other types</a></h3>
<p>
<ul>
<li><a href="seq_indices.html">Sequenced indices</a> allow to arrange
elements as in a bidirectional list.</li>
<li><a href="rnd_indices.html">Random access indices</a> provide
constant time positional access and free ordering of elements.</li>
</ul>
</p>
<h2><a name="views">Index views</a></h2>
<p>
The following concept is used by the rearrange facilities of non key-based
indices. Given an index <code>i</code> of type <code>Index</code>, a <i>view
of <code>i</code></i> is any range [<code>first</code>,<code>last</code>)
where <code>first</code> and <code>last</code> are input iterators such that
<ol>
<li>the associated value type of <code>Iterator</code> is convertible
to <code>const Index::value_type&amp;</code>
</li>
<li>and each of the elements of <code>i</code> appears exactly once in
[<code>first</code>,<code>last</code>).
</li>
</ol>
Note that the view refers to the actual elements of <code>i</code>, not to
copies of them. Additionally, a view is said to be <i>free</i> if its traversal
order is not affected by changes in the traversal order of <code>i</code>.
Examples of free views are:
<ul>
<li>[<code>c.begin()</code>,<code>c.end()</code>), where <code>c</code> is
any container of reference wrappers (from
<a href="../../../../doc/html/ref.html">Boost.Ref</a>) to the elements
of <code>i</code> containing exactly one reference to every element.
</li>
<li>[<code>i'.begin()</code>,<code>i'.end()</code>), where <code>i'</code> is
any index belonging to the same <code>multi_index_container</code>
as <code>i</code>, except <code>i</code> itself.
</li>
<li>
Any range which is a permutation of the ones described above, as for
instance [<code>c.rbegin()</code>,<code>c.rend()</code>), or
ranges obtained from the former with the aid of
<a href="../../../../libs/iterator/doc/permutation_iterator.html">
<code>permutation_iterator</code></a> from Boost.Iterator.
</li>
</ul>
</p>
<hr>
<div class="prev_link"><a href="multi_index_container.html"><img src="../prev.gif" alt="multi_index_container reference" border="0"><br>
<code>multi_index_container</code> reference
</a></div>
<div class="up_link"><a href="index.html"><img src="../up.gif" alt="Boost.MultiIndex reference" border="0"><br>
Boost.MultiIndex reference
</a></div>
<div class="next_link"><a href="ord_indices.html"><img src="../next.gif" alt="ordered indices" border="0"><br>
Ordered indices
</a></div><br clear="all" style="clear: all;">
<br>
<p>Revised April 19th 2015</p>
<p>&copy; Copyright 2003-2015 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz.
Distributed under the Boost Software
License, Version 1.0. (See accompanying file <a href="../../../../LICENSE_1_0.txt">
LICENSE_1_0.txt</a> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">
http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</body>
</html>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,645 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0.1 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Boost.MultiIndex Documentation - Ranked indices reference</title>
<link rel="stylesheet" href="../style.css" type="text/css">
<link rel="start" href="../index.html">
<link rel="prev" href="indices.html">
<link rel="up" href="index.html">
<link rel="next" href="hash_indices.html">
</head>
<body>
<h1><img src="../../../../boost.png" alt="boost.png (6897 bytes)" align=
"middle" width="277" height="86">Boost.MultiIndex Ranked indices reference</h1>
<div class="prev_link"><a href="ord_indices.html"><img src="../prev.gif" alt="ordered_indices" border="0"><br>
Ordered indices
</a></div>
<div class="up_link"><a href="index.html"><img src="../up.gif" alt="Boost.MultiIndex reference" border="0"><br>
Boost.MultiIndex reference
</a></div>
<div class="next_link"><a href="hash_indices.html"><img src="../next.gif" alt="hashed indices" border="0"><br>
Hashed indices
</a></div><br clear="all" style="clear: all;">
<hr>
<h2>Contents</h2>
<ul>
<li><a href="#rnk_index_fwd_synopsis">Header
<code>"boost/multi_index/ranked_index_fwd.hpp"</code> synopsis</a></li>
<li><a href="#synopsis">Header
<code>"boost/multi_index/ranked_index.hpp"</code> synopsis</a>
<ul>
<li><a href="#unique_non_unique">
Index specifiers <code>ranked_unique</code> and <code>ranked_non_unique</code>
</a></li>
<li><a href="#rnk_indices">Ranked indices</a>
<ul>
<li><a href="#complexity_signature">Complexity signature</a></li>
<li><a href="#instantiation_types">Instantiation types</a></li>
<li><a href="#rank_operations">Rank operations</a></li>
<li><a href="#serialization">Serialization</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<h2>
<a name="rnk_index_fwd_synopsis">Header
<a href="../../../../boost/multi_index/ranked_index_fwd.hpp">
<code>"boost/multi_index/ranked_index_fwd.hpp"</code></a> synopsis</a></h2>
<blockquote><pre>
<span class=keyword>namespace</span> <span class=identifier>boost</span><span class=special>{</span>
<span class=keyword>namespace</span> <span class=identifier>multi_index</span><span class=special>{</span>
<span class=comment>// index specifiers ranked_unique and ranked_non_unique</span>
<span class=keyword>template</span><span class=special>&lt;</span><b>consult ranked_unique reference for arguments</b><span class=special>&gt;</span>
<span class=keyword>struct</span> <span class=identifier>ranked_unique</span><span class=special>;</span>
<span class=keyword>template</span><span class=special>&lt;</span><b>consult ranked_non_unique reference for arguments</b><span class=special>&gt;</span>
<span class=keyword>struct</span> <span class=identifier>ranked_non_unique</span><span class=special>;</span>
<span class=comment>// indices</span>
<span class=keyword>namespace</span> <span class=identifier>detail</span><span class=special>{</span>
<span class=keyword>template</span><span class=special>&lt;</span><b>implementation defined</b><span class=special>&gt;</span> <span class=keyword>class</span> <b>index name is implementation defined</b><span class=special>;</span>
<span class=special>}</span> <span class=comment>// namespace boost::multi_index::detail</span>
<span class=special>}</span> <span class=comment>// namespace boost::multi_index</span>
<span class=special>}</span> <span class=comment>// namespace boost</span>
</pre></blockquote>
<p>
<code>ranked_index_fwd.hpp</code> provides forward declarations for index specifiers
<a href="#unique_non_unique"><code>ranked_unique</code> and <code>ranked_non_unique</code></a> and
their associated <a href="#rnk_indices">ranked index</a> classes.
</p>
<h2>
<a name="synopsis">Header
<a href="../../../../boost/multi_index/ranked_index.hpp">
<code>"boost/multi_index/ranked_index.hpp"</code></a> synopsis</a></h2>
<blockquote><pre>
<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>initializer_list</span><span class=special>&gt;</span>
<span class=keyword>namespace</span> <span class=identifier>boost</span><span class=special>{</span>
<span class=keyword>namespace</span> <span class=identifier>multi_index</span><span class=special>{</span>
<span class=comment>// index specifiers ranked_unique and ranked_non_unique</span>
<span class=keyword>template</span><span class=special>&lt;</span><b>consult ranked_unique reference for arguments</b><span class=special>&gt;</span>
<span class=keyword>struct</span> <span class=identifier>ranked_unique</span><span class=special>;</span>
<span class=keyword>template</span><span class=special>&lt;</span><b>consult ranked_non_unique reference for arguments</b><span class=special>&gt;</span>
<span class=keyword>struct</span> <span class=identifier>ranked_non_unique</span><span class=special>;</span>
<span class=comment>// indices</span>
<span class=keyword>namespace</span> <span class=identifier>detail</span><span class=special>{</span>
<span class=keyword>template</span><span class=special>&lt;</span><b>implementation defined</b><span class=special>&gt;</span> <span class=keyword>class</span> <b>index class name implementation defined</b><span class=special>;</span>
<span class=comment>// index comparison:</span>
<span class=comment>// <b>OP</b> is any of ==,&lt;,!=,&gt;,&gt;=,&lt;=</span>
<span class=keyword>template</span><span class=special>&lt;</span><b>arg set 1</b><span class=special>,</span><b>arg set 2</b><span class=special>&gt;</span>
<span class=keyword>bool</span> <span class=keyword>operator</span> <b><i>OP</i></b><span class=special>(</span>
<span class=keyword>const</span> <b>index class name</b><span class=special>&lt;</span><b>arg set 1</b><span class=special>&gt;&amp;</span> <span class=identifier>x</span><span class=special>,</span><span class=keyword>const</span> <b>index class name</b><span class=special>&lt;</span><b>arg set 2</b><span class=special>&gt;&amp;</span> <span class=identifier>y</span><span class=special>);</span>
<span class=comment>// index specialized algorithms:</span>
<span class=keyword>template</span><span class=special>&lt;</span><b>implementation defined</b><span class=special>&gt;</span>
<span class=keyword>void</span> <span class=identifier>swap</span><span class=special>(</span><b>index class name</b><span class=special>&amp;</span> <span class=identifier>x</span><span class=special>,</span><b>index class name</b><span class=special>&amp;</span> <span class=identifier>y</span><span class=special>);</span>
<span class=special>}</span> <span class=comment>// namespace boost::multi_index::detail</span>
<span class=special>}</span> <span class=comment>// namespace boost::multi_index</span>
<span class=special>}</span> <span class=comment>// namespace boost</span>
</pre></blockquote>
<h3><a name="unique_non_unique">
Index specifiers <code>ranked_unique</code> and <code>ranked_non_unique</code>
</a></h3>
<p>
These <a href="indices.html#index_specification">index specifiers</a> allow
for insertion of <a href="#rnk_indices">ranked indices</a> without and with
allowance of duplicate elements, respectively. The syntax of <code>ranked_unique</code>
and <code>ranked_non_unique</code> coincide, thus we describe them in a grouped manner.
<code>ranked_unique</code> and <code>ranked_non_unique</code> can be instantiated in
two different forms, according to whether a tag list for the index is provided or not:
</p>
<blockquote><pre>
<span class=keyword>template</span><span class=special>&lt;</span>
<span class=keyword>typename</span> <span class=identifier>KeyFromValue</span><span class=special>,</span>
<span class=keyword>typename</span> <span class=identifier>Compare</span><span class=special>=</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>less</span><span class=special>&lt;</span><span class=identifier>KeyFromValue</span><span class=special>::</span><span class=identifier>result_type</span><span class=special>&gt;</span>
<span class=special>&gt;</span>
<span class=keyword>struct</span> <span class=special>(</span><span class=identifier>ranked_unique</span> <span class=special>|</span> <span class=identifier>ranked_non_unique</span><span class=special>)</span><span class=special>;</span>
<span class=keyword>template</span><span class=special>&lt;</span>
<span class=keyword>typename</span> <span class=identifier>TagList</span><span class=special>,</span>
<span class=keyword>typename</span> <span class=identifier>KeyFromValue</span><span class=special>,</span>
<span class=keyword>typename</span> <span class=identifier>Compare</span><span class=special>=</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>less</span><span class=special>&lt;</span><span class=identifier>KeyFromValue</span><span class=special>::</span><span class=identifier>result_type</span><span class=special>&gt;</span>
<span class=special>&gt;</span>
<span class=keyword>struct</span> <span class=special>(</span><span class=identifier>ranked_unique</span> <span class=special>|</span> <span class=identifier>ranked_non_unique</span><span class=special>)</span><span class=special>;</span>
</pre></blockquote>
<p>
If provided, <code>TagList</code> must be an instantiation of the class template
<a href="indices.html#tag"><code>tag</code></a>.
The template arguments are used by the corresponding index implementation,
refer to the <a href="#rnk_indices">ranked indices</a> reference section for further
explanations on their acceptable type values.
</p>
<h3><a name="rnk_indices">Ranked indices</a></h3>
<p>
Ranked indices are a variation of <a href="ord_indices.html">ordered indices</a>
providing additional capabilities for calculation of and access by rank; the <i>rank</i> of an element is the
distance to it from the beginning of the index. Besides this extension, ranked indices replicate the
public interface of ordered indices with the difference, complexity-wise, that <a href="#complexity_signature">deletion</a>
is done in logarithmic rather than constant time. Also, execution times and memory consumption are
expected to be poorer due to the internal bookkeeping needed to maintain rank-related information.
As with ordered indices, ranked indices can be unique (no duplicate elements are allowed)
or non-unique: either version is associated to a different index specifier, but
the interface of both index types is the same.
</p>
<p>
In what follows, we only describe the extra operations provided by ranked indices: for the
rest refer to the <a href="ord_indices.html#ord_indices">documentation</a> for ordered
indices, bearing in mind the occasional differences in complexity.
</p>
<blockquote><pre>
<span class=keyword>namespace</span> <span class=identifier>boost</span><span class=special>{</span>
<span class=keyword>namespace</span> <span class=identifier>multi_index</span><span class=special>{</span>
<b>implementation defined </b><span class=identifier>unbounded</span><span class=special>;</span> <span class=comment>// see range_rank()</span>
<span class=keyword>namespace</span> <span class=identifier>detail</span><span class=special>{</span>
<span class=keyword>template</span><span class=special>&lt;</span><b>implementation defined: dependent on types Value, Allocator,
TagList, KeyFromValue, Compare</b><span class=special>&gt;</span>
<span class=keyword>class</span> <b>name is implementation defined</b>
<span class=special>{</span>
<span class=keyword>public</span><span class=special>:</span>
<span class=comment>// types:</span>
<span class=keyword>typedef</span> <span class=keyword>typename</span> <span class=identifier>KeyFromValue</span><span class=special>::</span><span class=identifier>result_type</span> <span class=identifier>key_type</span><span class=special>;</span>
<span class=keyword>typedef</span> <span class=identifier>Value</span> <span class=identifier>value_type</span><span class=special>;</span>
<span class=keyword>typedef</span> <span class=identifier>KeyFromValue</span> <span class=identifier>key_from_value</span><span class=special>;</span>
<span class=keyword>typedef</span> <span class=identifier>Compare</span> <span class=identifier>key_compare</span><span class=special>;</span>
<span class=keyword>typedef</span> <b>implementation defined </b><span class=identifier>value_compare</span><span class=special>;</span>
<span class=keyword>typedef</span> <span class=identifier>boost</span><span class=special>::</span><span class=identifier>tuple</span><span class=special>&lt;</span><span class=identifier>key_from_value</span><span class=special>,</span><span class=identifier>key_compare</span><span class=special>&gt;</span> <span class=identifier>ctor_args</span><span class=special>;</span>
<span class=keyword>typedef</span> <span class=identifier>TagList</span> <span class=identifier>tag_list</span><span class=special>;</span>
<span class=keyword>typedef</span> <span class=identifier>Allocator</span> <span class=identifier>allocator_type</span><span class=special>;</span>
<span class=keyword>typedef</span> <span class=keyword>typename</span> <span class=identifier>Allocator</span><span class=special>::</span><span class=identifier>reference</span> <span class=identifier>reference</span><span class=special>;</span>
<span class=keyword>typedef</span> <span class=keyword>typename</span> <span class=identifier>Allocator</span><span class=special>::</span><span class=identifier>const_reference</span> <span class=identifier>const_reference</span><span class=special>;</span>
<span class=keyword>typedef</span> <b>implementation defined </b><span class=identifier>iterator</span><span class=special>;</span>
<span class=keyword>typedef</span> <b>implementation defined </b><span class=identifier>const_iterator</span><span class=special>;</span>
<span class=keyword>typedef</span> <b>implementation defined </b><span class=identifier>size_type</span><span class=special>;</span>
<span class=keyword>typedef</span> <b>implementation defined </b><span class=identifier>difference_type</span><span class=special>;</span>
<span class=keyword>typedef</span> <span class=keyword>typename</span> <span class=identifier>Allocator</span><span class=special>::</span><span class=identifier>pointer</span> <span class=identifier>pointer</span><span class=special>;</span>
<span class=keyword>typedef</span> <span class=keyword>typename</span> <span class=identifier>Allocator</span><span class=special>::</span><span class=identifier>const_pointer</span> <span class=identifier>const_pointer</span><span class=special>;</span>
<span class=keyword>typedef</span> <b>equivalent to
std::reverse_iterator&lt;iterator&gt;</b> <span class=identifier>reverse_iterator</span><span class=special>;</span>
<span class=keyword>typedef</span> <b>equivalent to
std::reverse_iterator&lt;const_iterator&gt;</b> <span class=identifier>const_reverse_iterator</span><span class=special>;</span>
<span class=comment>// construct/copy/destroy:</span>
<b>index class name</b><span class=special>&amp;</span> <span class=keyword>operator</span><span class=special>=(</span><span class=keyword>const</span> <b>index class name</b><span class=special>&amp;</span> <span class=identifier>x</span><span class=special>);</span>
<b>index class name</b><span class=special>&amp;</span> <span class=keyword>operator</span><span class=special>=(</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>initializer_list</span><span class=special>&lt;</span><span class=identifier>value_type</span><span class=special>&gt;</span> <span class=identifier>list</span><span class=special>);</span>
<span class=identifier>allocator_type</span> <span class=identifier>get_allocator</span><span class=special>()</span><span class=keyword>const</span> <span class=keyword>noexcept</span><span class=special>;</span>
<span class=comment>// iterators:</span>
<span class=identifier>iterator</span> <span class=identifier>begin</span><span class=special>()</span><span class=keyword>noexcept</span><span class=special>;</span>
<span class=identifier>const_iterator</span> <span class=identifier>begin</span><span class=special>()</span><span class=keyword>const</span> <span class=keyword>noexcept</span><span class=special>;</span>
<span class=identifier>iterator</span> <span class=identifier>end</span><span class=special>()</span><span class=keyword>noexcept</span><span class=special>;</span>
<span class=identifier>const_iterator</span> <span class=identifier>end</span><span class=special>()</span><span class=keyword>const</span> <span class=keyword>noexcept</span><span class=special>;</span>
<span class=identifier>reverse_iterator</span> <span class=identifier>rbegin</span><span class=special>()</span><span class=keyword>noexcept</span><span class=special>;</span>
<span class=identifier>const_reverse_iterator</span> <span class=identifier>rbegin</span><span class=special>()</span><span class=keyword>const</span> <span class=keyword>noexcept</span><span class=special>;</span>
<span class=identifier>reverse_iterator</span> <span class=identifier>rend</span><span class=special>()</span><span class=keyword>noexcept</span><span class=special>;</span>
<span class=identifier>const_reverse_iterator</span> <span class=identifier>rend</span><span class=special>()</span><span class=keyword>const</span> <span class=keyword>noexcept</span><span class=special>;</span>
<span class=identifier>const_iterator</span> <span class=identifier>cbegin</span><span class=special>()</span><span class=keyword>const</span> <span class=keyword>noexcept</span><span class=special>;</span>
<span class=identifier>const_iterator</span> <span class=identifier>cend</span><span class=special>()</span><span class=keyword>const</span> <span class=keyword>noexcept</span><span class=special>;</span>
<span class=identifier>const_reverse_iterator</span> <span class=identifier>crbegin</span><span class=special>()</span><span class=keyword>const</span> <span class=keyword>noexcept</span><span class=special>;</span>
<span class=identifier>const_reverse_iterator</span> <span class=identifier>crend</span><span class=special>()</span><span class=keyword>const</span> <span class=keyword>noexcept</span><span class=special>;</span>
<span class=identifier>iterator</span> <span class=identifier>iterator_to</span><span class=special>(</span><span class=keyword>const</span> <span class=identifier>value_type</span><span class=special>&amp;</span> <span class=identifier>x</span><span class=special>);</span>
<span class=identifier>const_iterator</span> <span class=identifier>iterator_to</span><span class=special>(</span><span class=keyword>const</span> <span class=identifier>value_type</span><span class=special>&amp;</span> <span class=identifier>x</span><span class=special>)</span><span class=keyword>const</span><span class=special>;</span>
<span class=comment>// capacity:</span>
<span class=keyword>bool</span> <span class=identifier>empty</span><span class=special>()</span><span class=keyword>const</span> <span class=keyword>noexcept</span><span class=special>;</span>
<span class=identifier>size_type</span> <span class=identifier>size</span><span class=special>()</span><span class=keyword>const</span> <span class=keyword>noexcept</span><span class=special>;</span>
<span class=identifier>size_type</span> <span class=identifier>max_size</span><span class=special>()</span><span class=keyword>const</span> <span class=keyword>noexcept</span><span class=special>;</span>
<span class=comment>// modifiers:</span>
<span class=keyword>template</span><span class=special>&lt;</span><span class=keyword>typename</span><span class=special>...</span> <span class=identifier>Args</span><span class=special>&gt;</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>pair</span><span class=special>&lt;</span><span class=identifier>iterator</span><span class=special>,</span><span class=keyword>bool</span><span class=special>&gt;</span> <span class=identifier>emplace</span><span class=special>(</span><span class=identifier>Args</span><span class=special>&amp;&amp;...</span> <span class=identifier>args</span><span class=special>);</span>
<span class=keyword>template</span> <span class=special>&lt;</span><span class=keyword>typename</span><span class=special>...</span> <span class=identifier>Args</span><span class=special>&gt;</span>
<span class=identifier>iterator</span> <span class=identifier>emplace_hint</span><span class=special>(</span><span class=identifier>iterator</span> <span class=identifier>position</span><span class=special>,</span><span class=identifier>Args</span><span class=special>&amp;&amp;...</span> <span class=identifier>args</span><span class=special>);</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>pair</span><span class=special>&lt;</span><span class=identifier>iterator</span><span class=special>,</span><span class=keyword>bool</span><span class=special>&gt;</span> <span class=identifier>insert</span><span class=special>(</span><span class=keyword>const</span> <span class=identifier>value_type</span><span class=special>&amp;</span> <span class=identifier>x</span><span class=special>);</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>pair</span><span class=special>&lt;</span><span class=identifier>iterator</span><span class=special>,</span><span class=keyword>bool</span><span class=special>&gt;</span> <span class=identifier>insert</span><span class=special>(</span><span class=identifier>value_type</span><span class=special>&amp;&amp;</span> <span class=identifier>x</span><span class=special>);</span>
<span class=identifier>iterator</span> <span class=identifier>insert</span><span class=special>(</span><span class=identifier>iterator</span> <span class=identifier>position</span><span class=special>,</span><span class=keyword>const</span> <span class=identifier>value_type</span><span class=special>&amp;</span> <span class=identifier>x</span><span class=special>);</span>
<span class=identifier>iterator</span> <span class=identifier>insert</span><span class=special>(</span><span class=identifier>iterator</span> <span class=identifier>position</span><span class=special>,</span><span class=identifier>value_type</span><span class=special>&amp;&amp;</span> <span class=identifier>x</span><span class=special>);</span>
<span class=keyword>template</span><span class=special>&lt;</span><span class=keyword>typename</span> <span class=identifier>InputIterator</span><span class=special>&gt;</span>
<span class=keyword>void</span> <span class=identifier>insert</span><span class=special>(</span><span class=identifier>InputIterator</span> <span class=identifier>first</span><span class=special>,</span><span class=identifier>InputIterator</span> <span class=identifier>last</span><span class=special>);</span>
<span class=keyword>void</span> <span class=identifier>insert</span><span class=special>(</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>initializer_list</span><span class=special>&lt;</span><span class=identifier>value_type</span><span class=special>&gt;</span> <span class=identifier>list</span><span class=special>);</span>
<span class=identifier>iterator</span> <span class=identifier>erase</span><span class=special>(</span><span class=identifier>iterator</span> <span class=identifier>position</span><span class=special>);</span>
<span class=identifier>size_type</span> <span class=identifier>erase</span><span class=special>(</span><span class=keyword>const</span> <span class=identifier>key_type</span><span class=special>&amp;</span> <span class=identifier>x</span><span class=special>);</span>
<span class=identifier>iterator</span> <span class=identifier>erase</span><span class=special>(</span><span class=identifier>iterator</span> <span class=identifier>first</span><span class=special>,</span><span class=identifier>iterator</span> <span class=identifier>last</span><span class=special>);</span>
<span class=keyword>bool</span> <span class=identifier>replace</span><span class=special>(</span><span class=identifier>iterator</span> <span class=identifier>position</span><span class=special>,</span><span class=keyword>const</span> <span class=identifier>value_type</span><span class=special>&amp;</span> <span class=identifier>x</span><span class=special>);</span>
<span class=keyword>bool</span> <span class=identifier>replace</span><span class=special>(</span><span class=identifier>iterator</span> <span class=identifier>position</span><span class=special>,</span><span class=identifier>value_type</span><span class=special>&amp;&amp;</span> <span class=identifier>x</span><span class=special>);</span>
<span class=keyword>template</span><span class=special>&lt;</span><span class=keyword>typename</span> <span class=identifier>Modifier</span><span class=special>&gt;</span> <span class=keyword>bool</span> <span class=identifier>modify</span><span class=special>(</span><span class=identifier>iterator</span> <span class=identifier>position</span><span class=special>,</span><span class=identifier>Modifier</span> <span class=identifier>mod</span><span class=special>);</span>
<span class=keyword>template</span><span class=special>&lt;</span><span class=keyword>typename</span> <span class=identifier>Modifier</span><span class=special>,</span><span class=keyword>typename</span> <span class=identifier>Rollback</span><span class=special>&gt;</span>
<span class=keyword>bool</span> <span class=identifier>modify</span><span class=special>(</span><span class=identifier>iterator</span> <span class=identifier>position</span><span class=special>,</span><span class=identifier>Modifier</span> <span class=identifier>mod</span><span class=special>,</span><span class=identifier>Rollback</span> <span class=identifier>back</span><span class=special>);</span>
<span class=keyword>template</span><span class=special>&lt;</span><span class=keyword>typename</span> <span class=identifier>Modifier</span><span class=special>&gt;</span> <span class=keyword>bool</span> <span class=identifier>modify_key</span><span class=special>(</span><span class=identifier>iterator</span> <span class=identifier>position</span><span class=special>,</span><span class=identifier>Modifier</span> <span class=identifier>mod</span><span class=special>);</span>
<span class=keyword>template</span><span class=special>&lt;</span><span class=keyword>typename</span> <span class=identifier>Modifier</span><span class=special>,</span><span class=keyword>typename</span> <span class=identifier>Rollback</span><span class=special>&gt;</span>
<span class=keyword>bool</span> <span class=identifier>modify_key</span><span class=special>(</span><span class=identifier>iterator</span> <span class=identifier>position</span><span class=special>,</span><span class=identifier>Modifier</span> <span class=identifier>mod</span><span class=special>,</span><span class=identifier>Rollback</span> <span class=identifier>back</span><span class=special>);</span>
<span class=keyword>void</span> <span class=identifier>swap</span><span class=special>(</span><b>index class name</b><span class=special>&amp;</span> <span class=identifier>x</span><span class=special>);</span>
<span class=keyword>void</span> <span class=identifier>clear</span><span class=special>()</span><span class=keyword>noexcept</span><span class=special>;</span>
<span class=comment>// observers:</span>
<span class=identifier>key_from_value</span> <span class=identifier>key_extractor</span><span class=special>()</span><span class=keyword>const</span><span class=special>;</span>
<span class=identifier>key_compare</span> <span class=identifier>key_comp</span><span class=special>()</span><span class=keyword>const</span><span class=special>;</span>
<span class=identifier>value_compare</span> <span class=identifier>value_comp</span><span class=special>()</span><span class=keyword>const</span><span class=special>;</span>
<span class=comment>// set operations:</span>
<span class=keyword>template</span><span class=special>&lt;</span><span class=keyword>typename</span> <span class=identifier>CompatibleKey</span><span class=special>&gt;</span>
<span class=identifier>iterator</span> <span class=identifier>find</span><span class=special>(</span><span class=keyword>const</span> <span class=identifier>CompatibleKey</span><span class=special>&amp;</span> <span class=identifier>x</span><span class=special>)</span><span class=keyword>const</span><span class=special>;</span>
<span class=keyword>template</span><span class=special>&lt;</span><span class=keyword>typename</span> <span class=identifier>CompatibleKey</span><span class=special>,</span><span class=keyword>typename</span> <span class=identifier>CompatibleCompare</span><span class=special>&gt;</span>
<span class=identifier>iterator</span> <span class=identifier>find</span><span class=special>(</span>
<span class=keyword>const</span> <span class=identifier>CompatibleKey</span><span class=special>&amp;</span> <span class=identifier>x</span><span class=special>,</span><span class=keyword>const</span> <span class=identifier>CompatibleCompare</span><span class=special>&amp;</span> <span class=identifier>comp</span><span class=special>)</span><span class=keyword>const</span><span class=special>;</span>
<span class=keyword>template</span><span class=special>&lt;</span><span class=keyword>typename</span> <span class=identifier>CompatibleKey</span><span class=special>&gt;</span>
<span class=identifier>size_type</span> <span class=identifier>count</span><span class=special>(</span><span class=keyword>const</span> <span class=identifier>CompatibleKey</span><span class=special>&amp;</span> <span class=identifier>x</span><span class=special>)</span><span class=keyword>const</span><span class=special>;</span>
<span class=keyword>template</span><span class=special>&lt;</span><span class=keyword>typename</span> <span class=identifier>CompatibleKey</span><span class=special>,</span><span class=keyword>typename</span> <span class=identifier>CompatibleCompare</span><span class=special>&gt;</span>
<span class=identifier>size_type</span> <span class=identifier>count</span><span class=special>(</span><span class=keyword>const</span> <span class=identifier>CompatibleKey</span><span class=special>&amp;</span> <span class=identifier>x</span><span class=special>,</span><span class=keyword>const</span> <span class=identifier>CompatibleCompare</span><span class=special>&amp;</span> <span class=identifier>comp</span><span class=special>)</span><span class=keyword>const</span><span class=special>;</span>
<span class=keyword>template</span><span class=special>&lt;</span><span class=keyword>typename</span> <span class=identifier>CompatibleKey</span><span class=special>&gt;</span>
<span class=identifier>iterator</span> <span class=identifier>lower_bound</span><span class=special>(</span><span class=keyword>const</span> <span class=identifier>CompatibleKey</span><span class=special>&amp;</span> <span class=identifier>x</span><span class=special>)</span><span class=keyword>const</span><span class=special>;</span>
<span class=keyword>template</span><span class=special>&lt;</span><span class=keyword>typename</span> <span class=identifier>CompatibleKey</span><span class=special>,</span><span class=keyword>typename</span> <span class=identifier>CompatibleCompare</span><span class=special>&gt;</span>
<span class=identifier>iterator</span> <span class=identifier>lower_bound</span><span class=special>(</span>
<span class=keyword>const</span> <span class=identifier>CompatibleKey</span><span class=special>&amp;</span> <span class=identifier>x</span><span class=special>,</span><span class=keyword>const</span> <span class=identifier>CompatibleCompare</span><span class=special>&amp;</span> <span class=identifier>comp</span><span class=special>)</span><span class=keyword>const</span><span class=special>;</span>
<span class=keyword>template</span><span class=special>&lt;</span><span class=keyword>typename</span> <span class=identifier>CompatibleKey</span><span class=special>&gt;</span>
<span class=identifier>iterator</span> <span class=identifier>upper_bound</span><span class=special>(</span><span class=keyword>const</span> <span class=identifier>CompatibleKey</span><span class=special>&amp;</span> <span class=identifier>x</span><span class=special>)</span><span class=keyword>const</span><span class=special>;</span>
<span class=keyword>template</span><span class=special>&lt;</span><span class=keyword>typename</span> <span class=identifier>CompatibleKey</span><span class=special>,</span><span class=keyword>typename</span> <span class=identifier>CompatibleCompare</span><span class=special>&gt;</span>
<span class=identifier>iterator</span> <span class=identifier>upper_bound</span><span class=special>(</span>
<span class=keyword>const</span> <span class=identifier>CompatibleKey</span><span class=special>&amp;</span> <span class=identifier>x</span><span class=special>,</span><span class=keyword>const</span> <span class=identifier>CompatibleCompare</span><span class=special>&amp;</span> <span class=identifier>comp</span><span class=special>)</span><span class=keyword>const</span><span class=special>;</span>
<span class=keyword>template</span><span class=special>&lt;</span><span class=keyword>typename</span> <span class=identifier>CompatibleKey</span><span class=special>&gt;</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>pair</span><span class=special>&lt;</span><span class=identifier>iterator</span><span class=special>,</span><span class=identifier>iterator</span><span class=special>&gt;</span> <span class=identifier>equal_range</span><span class=special>(</span>
<span class=keyword>const</span> <span class=identifier>CompatibleKey</span><span class=special>&amp;</span> <span class=identifier>x</span><span class=special>)</span><span class=keyword>const</span><span class=special>;</span>
<span class=keyword>template</span><span class=special>&lt;</span><span class=keyword>typename</span> <span class=identifier>CompatibleKey</span><span class=special>,</span><span class=keyword>typename</span> <span class=identifier>CompatibleCompare</span><span class=special>&gt;</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>pair</span><span class=special>&lt;</span><span class=identifier>iterator</span><span class=special>,</span><span class=identifier>iterator</span><span class=special>&gt;</span> <span class=identifier>equal_range</span><span class=special>(</span>
<span class=keyword>const</span> <span class=identifier>CompatibleKey</span><span class=special>&amp;</span> <span class=identifier>x</span><span class=special>,</span><span class=keyword>const</span> <span class=identifier>CompatibleCompare</span><span class=special>&amp;</span> <span class=identifier>comp</span><span class=special>)</span><span class=keyword>const</span><span class=special>;</span>
<span class=comment>// range:</span>
<span class=keyword>template</span><span class=special>&lt;</span><span class=keyword>typename</span> <span class=identifier>LowerBounder</span><span class=special>,</span><span class=keyword>typename</span> <span class=identifier>UpperBounder</span><span class=special>&gt;</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>pair</span><span class=special>&lt;</span><span class=identifier>iterator</span><span class=special>,</span><span class=identifier>iterator</span><span class=special>&gt;</span> <span class=identifier>range</span><span class=special>(</span>
<span class=identifier>LowerBounder</span> <span class=identifier>lower</span><span class=special>,</span><span class=identifier>UpperBounder</span> <span class=identifier>upper</span><span class=special>)</span><span class=keyword>const</span><span class=special>;</span>
<span class=comment>// rank operations:</span>
<span class=identifier>iterator</span> <span class=identifier>nth</span><span class=special>(</span><span class=identifier>size_type</span> <span class=identifier>n</span><span class=special>)</span><span class=keyword>const</span><span class=special>;</span>
<span class=identifier>size_type</span> <span class=identifier>rank</span><span class=special>(</span><span class=identifier>iterator</span> <span class=identifier>position</span><span class=special>)</span><span class=keyword>const</span><span class=special>;</span>
<span class=keyword>template</span><span class=special>&lt;</span><span class=keyword>typename</span> <span class=identifier>CompatibleKey</span><span class=special>&gt;</span>
<span class=identifier>size_type</span> <span class=identifier>find_rank</span><span class=special>(</span><span class=keyword>const</span> <span class=identifier>CompatibleKey</span><span class=special>&amp;</span> <span class=identifier>x</span><span class=special>)</span><span class=keyword>const</span><span class=special>;</span>
<span class=keyword>template</span><span class=special>&lt;</span><span class=keyword>typename</span> <span class=identifier>CompatibleKey</span><span class=special>,</span><span class=keyword>typename</span> <span class=identifier>CompatibleCompare</span><span class=special>&gt;</span>
<span class=identifier>size_type</span> <span class=identifier>find_rank</span><span class=special>(</span>
<span class=keyword>const</span> <span class=identifier>CompatibleKey</span><span class=special>&amp;</span> <span class=identifier>x</span><span class=special>,</span><span class=keyword>const</span> <span class=identifier>CompatibleCompare</span><span class=special>&amp;</span> <span class=identifier>comp</span><span class=special>)</span><span class=keyword>const</span><span class=special>;</span>
<span class=keyword>template</span><span class=special>&lt;</span><span class=keyword>typename</span> <span class=identifier>CompatibleKey</span><span class=special>&gt;</span>
<span class=identifier>size_type</span> <span class=identifier>lower_bound_rank</span><span class=special>(</span><span class=keyword>const</span> <span class=identifier>CompatibleKey</span><span class=special>&amp;</span> <span class=identifier>x</span><span class=special>)</span><span class=keyword>const</span><span class=special>;</span>
<span class=keyword>template</span><span class=special>&lt;</span><span class=keyword>typename</span> <span class=identifier>CompatibleKey</span><span class=special>,</span><span class=keyword>typename</span> <span class=identifier>CompatibleCompare</span><span class=special>&gt;</span>
<span class=identifier>size_type</span> <span class=identifier>lower_bound_rank</span><span class=special>(</span>
<span class=keyword>const</span> <span class=identifier>CompatibleKey</span><span class=special>&amp;</span> <span class=identifier>x</span><span class=special>,</span><span class=keyword>const</span> <span class=identifier>CompatibleCompare</span><span class=special>&amp;</span> <span class=identifier>comp</span><span class=special>)</span><span class=keyword>const</span><span class=special>;</span>
<span class=keyword>template</span><span class=special>&lt;</span><span class=keyword>typename</span> <span class=identifier>CompatibleKey</span><span class=special>&gt;</span>
<span class=identifier>size_type</span> <span class=identifier>upper_bound_rank</span><span class=special>(</span><span class=keyword>const</span> <span class=identifier>CompatibleKey</span><span class=special>&amp;</span> <span class=identifier>x</span><span class=special>)</span><span class=keyword>const</span><span class=special>;</span>
<span class=keyword>template</span><span class=special>&lt;</span><span class=keyword>typename</span> <span class=identifier>CompatibleKey</span><span class=special>,</span><span class=keyword>typename</span> <span class=identifier>CompatibleCompare</span><span class=special>&gt;</span>
<span class=identifier>size_type</span> <span class=identifier>upper_bound_rank</span><span class=special>(</span>
<span class=keyword>const</span> <span class=identifier>CompatibleKey</span><span class=special>&amp;</span> <span class=identifier>x</span><span class=special>,</span><span class=keyword>const</span> <span class=identifier>CompatibleCompare</span><span class=special>&amp;</span> <span class=identifier>comp</span><span class=special>)</span><span class=keyword>const</span><span class=special>;</span>
<span class=keyword>template</span><span class=special>&lt;</span><span class=keyword>typename</span> <span class=identifier>CompatibleKey</span><span class=special>&gt;</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>pair</span><span class=special>&lt;</span><span class=identifier>size_type</span><span class=special>,</span><span class=identifier>size_type</span><span class=special>&gt;</span> <span class=identifier>equal_range_rank</span><span class=special>(</span>
<span class=keyword>const</span> <span class=identifier>CompatibleKey</span><span class=special>&amp;</span> <span class=identifier>x</span><span class=special>)</span><span class=keyword>const</span><span class=special>;</span>
<span class=keyword>template</span><span class=special>&lt;</span><span class=keyword>typename</span> <span class=identifier>CompatibleKey</span><span class=special>,</span><span class=keyword>typename</span> <span class=identifier>CompatibleCompare</span><span class=special>&gt;</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>pair</span><span class=special>&lt;</span><span class=identifier>size_type</span><span class=special>,</span><span class=identifier>size_type</span><span class=special>&gt;</span> <span class=identifier>equal_range_rank</span><span class=special>(</span>
<span class=keyword>const</span> <span class=identifier>CompatibleKey</span><span class=special>&amp;</span> <span class=identifier>x</span><span class=special>,</span><span class=keyword>const</span> <span class=identifier>CompatibleCompare</span><span class=special>&amp;</span> <span class=identifier>comp</span><span class=special>)</span><span class=keyword>const</span><span class=special>;</span>
<span class=keyword>template</span><span class=special>&lt;</span><span class=keyword>typename</span> <span class=identifier>LowerBounder</span><span class=special>,</span><span class=keyword>typename</span> <span class=identifier>UpperBounder</span><span class=special>&gt;</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>pair</span><span class=special>&lt;</span><span class=identifier>size_type</span><span class=special>,</span><span class=identifier>size_type</span><span class=special>&gt;</span>
<span class=identifier>range_rank</span><span class=special>(</span><span class=identifier>LowerBounder</span> <span class=identifier>lower</span><span class=special>,</span><span class=identifier>UpperBounder</span> <span class=identifier>upper</span><span class=special>)</span><span class=keyword>const</span><span class=special>;</span>
<span class=special>};</span>
<span class=comment>// index comparison:</span>
<span class=keyword>template</span><span class=special>&lt;</span><b>arg set 1</b><span class=special>,</span><b>arg set 2</b><span class=special>&gt;</span>
<span class=keyword>bool</span> <span class=keyword>operator</span><span class=special>==(</span>
<span class=keyword>const</span> <b>index class name</b><span class=special>&lt;</span><b>arg set 1</b><span class=special>&gt;&amp;</span> <span class=identifier>x</span><span class=special>,</span>
<span class=keyword>const</span> <b>index class name</b><span class=special>&lt;</span><b>arg set 2</b><span class=special>&gt;&amp;</span> <span class=identifier>y</span><span class=special>)</span>
<span class=special>{</span>
<span class=keyword>return</span> <span class=identifier>x</span><span class=special>.</span><span class=identifier>size</span><span class=special>()==</span><span class=identifier>y</span><span class=special>.</span><span class=identifier>size</span><span class=special>()&amp;&amp;</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>equal</span><span class=special>(</span><span class=identifier>x</span><span class=special>.</span><span class=identifier>begin</span><span class=special>(),</span><span class=identifier>x</span><span class=special>.</span><span class=identifier>end</span><span class=special>(),</span><span class=identifier>y</span><span class=special>.</span><span class=identifier>begin</span><span class=special>());</span>
<span class=special>}</span>
<span class=keyword>template</span><span class=special>&lt;</span><b>arg set 1</b><span class=special>,</span><b>arg set 2</b><span class=special>&gt;</span>
<span class=keyword>bool</span> <span class=keyword>operator</span><span class=special>&lt;(</span>
<span class=keyword>const</span> <b>index class name</b><span class=special>&lt;</span><b>arg set 1</b><span class=special>&gt;&amp;</span> <span class=identifier>x</span><span class=special>,</span>
<span class=keyword>const</span> <b>index class name</b><span class=special>&lt;</span><b>arg set 2</b><span class=special>&gt;&amp;</span> <span class=identifier>y</span><span class=special>)</span>
<span class=special>{</span>
<span class=keyword>return</span> <span class=identifier>std</span><span class=special>::</span><span class=identifier>lexicographical_compare</span><span class=special>(</span><span class=identifier>x</span><span class=special>.</span><span class=identifier>begin</span><span class=special>(),</span><span class=identifier>x</span><span class=special>.</span><span class=identifier>end</span><span class=special>(),</span><span class=identifier>y</span><span class=special>.</span><span class=identifier>begin</span><span class=special>(),</span><span class=identifier>y</span><span class=special>.</span><span class=identifier>end</span><span class=special>());</span>
<span class=special>}</span>
<span class=keyword>template</span><span class=special>&lt;</span><b>arg set 1</b><span class=special>,</span><b>arg set 2</b><span class=special>&gt;</span>
<span class=keyword>bool</span> <span class=keyword>operator</span><span class=special>!=(</span>
<span class=keyword>const</span> <b>index class name</b><span class=special>&lt;</span><b>arg set 1</b><span class=special>&gt;&amp;</span> <span class=identifier>x</span><span class=special>,</span>
<span class=keyword>const</span> <b>index class name</b><span class=special>&lt;</span><b>arg set 2</b><span class=special>&gt;&amp;</span> <span class=identifier>y</span><span class=special>)</span>
<span class=special>{</span>
<span class=keyword>return</span> <span class=special>!(</span><span class=identifier>x</span><span class=special>==</span><span class=identifier>y</span><span class=special>);</span>
<span class=special>}</span>
<span class=keyword>template</span><span class=special>&lt;</span><b>arg set 1</b><span class=special>,</span><b>arg set 2</b><span class=special>&gt;</span>
<span class=keyword>bool</span> <span class=keyword>operator</span><span class=special>&gt;(</span>
<span class=keyword>const</span> <b>index class name</b><span class=special>&lt;</span><b>arg set 1</b><span class=special>&gt;&amp;</span> <span class=identifier>x</span><span class=special>,</span>
<span class=keyword>const</span> <b>index class name</b><span class=special>&lt;</span><b>arg set 2</b><span class=special>&gt;&amp;</span> <span class=identifier>y</span><span class=special>)</span>
<span class=special>{</span>
<span class=keyword>return</span> <span class=identifier>y</span><span class=special>&lt;</span><span class=identifier>x</span><span class=special>;</span>
<span class=special>}</span>
<span class=keyword>template</span><span class=special>&lt;</span><b>arg set 1</b><span class=special>,</span><b>arg set 2</b><span class=special>&gt;</span>
<span class=keyword>bool</span> <span class=keyword>operator</span><span class=special>&gt;=(</span>
<span class=keyword>const</span> <b>index class name</b><span class=special>&lt;</span><b>arg set 1</b><span class=special>&gt;&amp;</span> <span class=identifier>x</span><span class=special>,</span>
<span class=keyword>const</span> <b>index class name</b><span class=special>&lt;</span><b>arg set 2</b><span class=special>&gt;&amp;</span> <span class=identifier>y</span><span class=special>)</span>
<span class=special>{</span>
<span class=keyword>return</span> <span class=special>!(</span><span class=identifier>x</span><span class=special>&lt;</span><span class=identifier>y</span><span class=special>);</span>
<span class=special>}</span>
<span class=keyword>template</span><span class=special>&lt;</span><b>arg set 1</b><span class=special>,</span><b>arg set 2</b><span class=special>&gt;</span>
<span class=keyword>bool</span> <span class=keyword>operator</span><span class=special>&lt;=(</span>
<span class=keyword>const</span> <b>index class name</b><span class=special>&lt;</span><b>arg set 1</b><span class=special>&gt;&amp;</span> <span class=identifier>x</span><span class=special>,</span>
<span class=keyword>const</span> <b>index class name</b><span class=special>&lt;</span><b>arg set 2</b><span class=special>&gt;&amp;</span> <span class=identifier>y</span><span class=special>)</span>
<span class=special>{</span>
<span class=keyword>return</span> <span class=special>!(</span><span class=identifier>x</span><span class=special>&gt;</span><span class=identifier>y</span><span class=special>);</span>
<span class=special>}</span>
<span class=comment>// index specialized algorithms:</span>
<span class=keyword>template</span><span class=special>&lt;</span><b>implementation defined</b><span class=special>&gt;</span>
<span class=keyword>void</span> <span class=identifier>swap</span><span class=special>(</span><b>index class name</b><span class=special>&amp;</span> <span class=identifier>x</span><span class=special>,</span><b>index class name</b><span class=special>&amp;</span> <span class=identifier>y</span><span class=special>);</span>
<span class=special>}</span> <span class=comment>// namespace boost::multi_index::detail</span>
<span class=special>}</span> <span class=comment>// namespace boost::multi_index</span>
<span class=special>}</span> <span class=comment>// namespace boost</span>
</pre></blockquote>
<h4><a name="complexity_signature">Complexity signature</a></h4>
<p>
We follow the terminology described in the
<a href="indices.html#complexity_signature">complexity signature
section</a>. The complexity signature of ranked indices is:
<ul>
<li>copying: <code>c(n)=n*log(n)</code>,</li>
<li>insertion: <code>i(n)=log(n)</code>,</li>
<li>hinted insertion: <code>h(n)=1</code> (constant) if the hint element
is immediately after the point of insertion, <code>h(n)=log(n)</code> otherwise,</li>
<li>deletion: <b><code>d(n)=log(n)</code></b> ,</li>
<li>replacement: <code>r(n)=1</code> (constant) if the element position does not
change, <code>r(n)=log(n)</code> otherwise,</li>
<li>modifying: <code>m(n)=1</code> (constant) if the element position does not
change, <code>m(n)=log(n)</code> otherwise.</li>
</ul>
</p>
<p>
These complexity guarantees are the same as those of
<a href="ord_indices.html#complexity_signature">ordered indices</a>
except for deletion, which is <code>log(n)</code> here and amortized constant there.
</p>
<h4><a name="instantiation_types">Instantiation types</a></h4>
<p>Ordered indices are instantiated internally to <code>multi_index_container</code> and
specified by means of <a href="indices.html#indexed_by"><code>indexed_by</code></a>
with <a href="#unique_non_unique"> index specifiers <code>ranked_unique</code>
and <code>ranked_non_unique</code></a>. Instantiations are dependent on the
following types:
<ul>
<li><code>Value</code> from <code>multi_index_container</code>,</li>
<li><code>Allocator</code> from <code>multi_index_container</code>,</li>
<li><code>TagList</code> from the index specifier (if provided, otherwise <code>tag&lt;&gt;</code> is assumed),</li>
<li><code>KeyFromValue</code> from the index specifier,</li>
<li><code>Compare</code> from the index specifier.</li>
</ul>
These types are subject to the same requirements as specified for
<a href="ord_indices.html#instantiation_types">ordered indices</a>.
</p>
<h4><a name="rank_operations">Rank operations</a></h4>
<p>
The <i>rank</i> of an iterator <code>it</code> of a given container <code>c</code> (and,
by extension, of the element it points to if the iterator is dereferenceable)
is <code>std::distance(c.begin(),it)</code>.
</p>
<p>
See the documentation of ordered indices for an explanation of the notions of
<a href="ord_indices.html#set_operations"><i>compatible extension</i>,
<i>compatible key</i></a>,
<a href="ord_indices.html#range_operations"><i>lower bounder</i> and <i>upper bounder</i></a>, which are
referred to below.
</p>
<code>iterator nth(size_type n)const;</code>
<blockquote>
<b>Effects:</b> Returns an iterator with rank <code>n</code>,
or <code>end()</code> if <code>n&gt;=size()</code>.<br>
<b>Complexity:</b> <code>O(log(n))</code>.<br>
</blockquote>
<code>size_type rank(iterator position)const;
</code>
<blockquote>
<b>Requires:</b> <code>position</code> is a valid iterator of the index.<br>
<b>Effects:</b> Returns the rank of <code>position</code>.<br>
<b>Complexity:</b> <code>O(log(n))</code>.<br>
</blockquote>
<code>template&lt;typename CompatibleKey> size_type find_rank(const CompatibleKey&amp; x)const;
</code>
<blockquote>
<b>Requires:</b> <code>CompatibleKey</code> is a compatible key of
<code>key_compare</code>.<br>
<b>Effects:</b> Equivalent to <code>rank(find(k))</code>.<br>
<b>Complexity:</b> <code>O(log(n))</code>.<br>
</blockquote>
<code>template&lt;typename CompatibleKey,typename CompatibleCompare><br>
size_type find_rank(const CompatibleKey&amp; x,const CompatibleCompare&amp; comp)const;
</code>
<blockquote>
<b>Requires:</b> (<code>CompatibleKey</code>, <code>CompatibleCompare</code>)
is a compatible extension of <code>key_compare</code>.<br>
<b>Effects:</b> Equivalent to <code>rank(find(x,comp))</code>.<br>
<b>Complexity:</b> <code>O(log(n))</code>.<br>
</blockquote>
<code>template&lt;typename CompatibleKey><br>
size_type lower_bound_rank(const CompatibleKey&amp; x)const;
</code>
<blockquote>
<b>Requires:</b> <code>CompatibleKey</code> is a compatible key of
<code>key_compare</code>.<br>
<b>Effects:</b> Equivalent to <code>rank(lower_bound(x))</code>.<br>
<b>Complexity:</b> <code>O(log(n))</code>.<br>
</blockquote>
<code>template&lt;typename CompatibleKey,typename CompatibleCompare><br>
size_type lower_bound_rank(const CompatibleKey&amp; x,const CompatibleCompare&amp; comp)const;
</code>
<blockquote>
<b>Requires:</b> (<code>CompatibleKey</code>, <code>CompatibleCompare</code>)
is a compatible extension of <code>key_compare</code>.<br>
<b>Effects:</b> Equivalent to <code>rank(lower_bound(x,comp))</code>.<br>
<b>Complexity:</b> <code>O(log(n))</code>.<br>
</blockquote>
<code>template&lt;typename CompatibleKey><br>
size_type upper_bound_rank(const CompatibleKey&amp; x)const;
</code>
<blockquote>
<b>Requires:</b> <code>CompatibleKey</code> is a compatible key of
<code>key_compare</code>.<br>
<b>Effects:</b> Equivalent to <code>rank(upper_bound(x))</code>.<br>
<b>Complexity:</b> <code>O(log(n))</code>.<br>
</blockquote>
<code>template&lt;typename CompatibleKey,typename CompatibleCompare><br>
size_type upper_bound_rank(const CompatibleKey&amp; x,const CompatibleCompare&amp; comp)const;
</code>
<blockquote>
<b>Requires:</b> (<code>CompatibleKey</code>, <code>CompatibleCompare</code>)
is a compatible extension of <code>key_compare</code>.<br>
<b>Effects:</b> Equivalent to <code>rank(upper_bound(x,comp))</code>.<br>
<b>Complexity:</b> <code>O(log(n))</code>.<br>
</blockquote>
<code>template&lt;typename CompatibleKey><br>
std::pair&lt;size_type,size_type> equal_range_rank(<br>
&nbsp;&nbsp;const CompatibleKey&amp; x)const;
</code>
<blockquote>
<b>Requires:</b> <code>CompatibleKey</code> is a compatible key of
<code>key_compare</code>.<br>
<b>Effects:</b> Equivalent to <code>make_pair(lower_bound_rank(x),upper_bound_rank(x))</code>.<br>
<b>Complexity:</b> <code>O(log(n))</code>.<br>
</blockquote>
<code>template&lt;typename CompatibleKey,typename CompatibleCompare><br>
std::pair&lt;size_type,size_type> equal_range_rank(<br>
&nbsp;&nbsp;const CompatibleKey&amp; x,const CompatibleCompare&amp; comp)const;
</code>
<blockquote>
<b>Requires:</b> (<code>CompatibleKey</code>, <code>CompatibleCompare</code>)
is a compatible extension of <code>key_compare</code>.<br>
<b>Effects:</b> Equivalent to
<code>make_pair(lower_bound_rank(x,comp),upper_bound_rank(x,comp))</code>.<br>
<b>Complexity:</b> <code>O(log(n))</code>.<br>
</blockquote>
<code>template&lt;typename LowerBounder,typename UpperBounder><br>
std::pair&lt;size_type,size_type> range_rank(<br>
&nbsp;&nbsp;LowerBounder lower,UpperBounder upper)const;
</code>
<blockquote>
<b>Requires:</b> <code>LowerBounder</code> and <code>UpperBounder</code> are
a lower and upper bounder of <code>key_compare</code>, respectively.<br>
<b>Effects:</b> Equivalent to
<blockquote><pre>
<span class=keyword>auto</span> <span class=identifier>p</span><span class=special>=</span><span class=identifier>range</span><span class=special>(</span><span class=identifier>lower</span><span class=special>,</span><span class=identifier>upper</span><span class=special>);</span>
<span class=keyword>return</span> <span class=identifier>make_pair</span><span class=special>(</span><span class=identifier>rank</span><span class=special>(</span><span class=identifier>p</span><span class=special>.</span><span class=identifier>first</span><span class=special>),</span><span class=identifier>rank</span><span class=special>(</span><span class=identifier>p</span><span class=special>.</span><span class=identifier>second</span><span class=special>));</span>
</pre></blockquote>
<b>Complexity:</b> <code>O(log(n))</code>.<br>
<b>Variants:</b> In place of <code>lower</code> or <code>upper</code> (or both),
the singular value <code>boost::multi_index::unbounded</code> can be
provided. This acts as a predicate which all values of type <code>key_type</code>
satisfy.<br>
</blockquote>
<h4><a name="serialization">Serialization</a></h4>
<p>
The prerequisites and postconditions associated to serialization of
<code>multi_index_container</code>s with ranked indices are exactly the same
as those of <a href="ord_indices.html#serialization">ordered indices</a>.
<hr>
<div class="prev_link"><a href="ord_indices.html"><img src="../prev.gif" alt="ordered_indices" border="0"><br>
Ordered indices
</a></div>
<div class="up_link"><a href="index.html"><img src="../up.gif" alt="Boost.MultiIndex reference" border="0"><br>
Boost.MultiIndex reference
</a></div>
<div class="next_link"><a href="hash_indices.html"><img src="../next.gif" alt="hashed indices" border="0"><br>
Hashed indices
</a></div><br clear="all" style="clear: all;">
<br>
<p>Revised May 4th 2015</p>
<p>&copy; Copyright 2003-2015 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz.
Distributed under the Boost Software
License, Version 1.0. (See accompanying file <a href="../../../../LICENSE_1_0.txt">
LICENSE_1_0.txt</a> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">
http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,567 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0.1 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Boost.MultiIndex Documentation - Release notes</title>
<link rel="stylesheet" href="style.css" type="text/css">
<link rel="start" href="index.html">
<link rel="prev" href="future_work.html">
<link rel="up" href="index.html">
<link rel="next" href="acknowledgements.html">
</head>
<body>
<h1><img src="../../../boost.png" alt="boost.png (6897 bytes)" align=
"middle" width="277" height="86">Boost.MultiIndex Release notes</h1>
<div class="prev_link"><a href="future_work.html"><img src="prev.gif" alt="future work" border="0"><br>
Future work
</a></div>
<div class="up_link"><a href="index.html"><img src="up.gif" alt="index" border="0"><br>
Index
</a></div>
<div class="next_link"><a href="acknowledgements.html"><img src="next.gif" alt="acknowledgements" border="0"><br>
Acknowledgements
</a></div><br clear="all" style="clear: all;">
<hr>
<h2>Contents</h2>
<ul>
<li><a href="#boost_1_66">Boost 1.66 release</a></li>
<li><a href="#boost_1_64">Boost 1.64 release</a></li>
<li><a href="#boost_1_62">Boost 1.62 release</a></li>
<li><a href="#boost_1_60">Boost 1.60 release</a></li>
<li><a href="#boost_1_59">Boost 1.59 release</a></li>
<li><a href="#boost_1_58">Boost 1.58 release</a></li>
<li><a href="#boost_1_57">Boost 1.57 release</a></li>
<li><a href="#boost_1_56">Boost 1.56 release</a></li>
<li><a href="#boost_1_55">Boost 1.55 release</a></li>
<li><a href="#boost_1_54">Boost 1.54 release</a></li>
<li><a href="#boost_1_49">Boost 1.49 release</a></li>
<li><a href="#boost_1_48">Boost 1.48 release</a></li>
<li><a href="#boost_1_47">Boost 1.47 release</a></li>
<li><a href="#boost_1_44">Boost 1.44 release</a></li>
<li><a href="#boost_1_43">Boost 1.43 release</a></li>
<li><a href="#boost_1_42">Boost 1.42 release</a></li>
<li><a href="#boost_1_41">Boost 1.41 release</a></li>
<li><a href="#boost_1_38">Boost 1.38 release</a></li>
<li><a href="#boost_1_37">Boost 1.37 release</a></li>
<li><a href="#boost_1_36">Boost 1.36 release</a></li>
<li><a href="#boost_1_35">Boost 1.35 release</a></li>
<li><a href="#boost_1_34">Boost 1.34 release</a></li>
<li><a href="#boost_1_33_1">Boost 1.33.1 release</a></li>
<li><a href="#boost_1_33">Boost 1.33 release</a></li>
</ul>
<h2><a name="boost_1_66">Boost 1.66 release</a></h2>
<p>
<ul>
<li>Made <code>modify</code> and <code>modify_key</code> more robust so that
the modified element is erased if the modifier throws or the rollback
functor does not properly restore the element (full discussion at
ticket <a href="https://svn.boost.org/trac/boost/ticket/12542">#12542</a>).
This is technically backwards incompatible; for instance, the following code:
<blockquote><pre>
<span class=identifier>c</span><span class=special>.</span><span class=identifier>modify</span><span class=special>(</span><span class=identifier>c</span><span class=special>.</span><span class=identifier>begin</span><span class=special>(),[](</span><span class=keyword>auto</span><span class=special>&amp;){</span><span class=keyword>throw</span> <span class=number>0</span><span class=special>;});</span>
</pre></blockquote>
keeps the container <code>c</code> untouched in former versions of Boost whereas
now <code>c.begin()</code> is erased. Thanks to Jon Kalb for raising the issue.
</li>
<li>Maintenance fixes.</li>
</ul>
</p>
<h2><a name="boost_1_64">Boost 1.64 release</a></h2>
<p>
<ul>
<li>Fixed a bug related to ambiguous references in the presence of more than
one ranked index
(ticket <a href="https://svn.boost.org/trac/boost/ticket/12955">#12955</a>).
</li>
<li>Maintenance fixes.</li>
</ul>
</p>
<h2><a name="boost_1_62">Boost 1.62 release</a></h2>
<p>
<ul>
<li>Maintenance fixes.</li>
</ul>
</p>
<h2><a name="boost_1_60">Boost 1.60 release</a></h2>
<p>
<ul>
<li>Fixed an interoperability problem with <a href="http://www.qt.io/">Qt</a> due to the
optional definition of a macro with name <code>foreach</code> in this framework.</li>
<li>Maintenance fixes.</li>
</ul>
</p>
<h2><a name="boost_1_59">Boost 1.59 release</a></h2>
<p>
<ul>
<li>Added <a href="tutorial/indices.html#rnk_indices">ranked indices</a>.</li>
<li>Maintenance fixes.</li>
</ul>
</p>
<h2><a name="boost_1_58">Boost 1.58 release</a></h2>
<p>
<ul>
<li>The efficiency of lookup operations has improved in situations where they involve
the generation of temporary values of <code>key_type</code>. Consider for instance
the following code:
<blockquote><pre>
<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special>&lt;</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>,</span>
<span class=identifier>indexed_by</span><span class=special>&lt;</span>
<span class=identifier>ordered_unique</span><span class=special>&lt;</span><span class=identifier>identity</span><span class=special>&lt;</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>&gt;</span> <span class=special>&gt;</span>
<span class=special>&gt;</span>
<span class=special>&gt;</span> <span class=identifier>multi_t</span><span class=special>;</span>
<span class=special>...</span>
<span class=identifier>multi_t</span> <span class=identifier>m</span><span class=special>=...;</span>
<span class=identifier>m</span><span class=special>.</span><span class=identifier>find</span><span class=special>(</span><span class=string>&quot;boost&quot;</span><span class=special>);</span> <span class=comment>// passed a const char*, not a std::string</span>
</pre></blockquote>
In previous versions of the library, the <code>find</code> operation generates
several temporary <code>std::string</code>s (one every time an internal comparison is made).
In sufficiently advanced compilers, this is now avoided so that only one temporary is
created.
</li>
<li>Maintenance fixes.</li>
</ul>
</p>
<h2><a name="boost_1_57">Boost 1.57 release</a></h2>
<p>
<ul>
<li>When <code>std::tuple</code>s are available, these can be used for lookup operations
in indices equipped with composite keys. <code>boost::tuple</code>s are also supported
for backwards compatibility.
</li>
</ul>
</p>
<h2><a name="boost_1_56">Boost 1.56 release</a></h2>
<p>
<ul>
<li>The <code>erase(iterator)</code> member function of hashed indices
used to have poor performance under low load conditions due to the requirement
that an iterator to the next element must be returned (see ticket
<a href="https://svn.boost.org/trac/boost/ticket/4264">#4264</a>). In accordance with
the resolution of <a href="http://lwg.github.io/issues/lwg-closed.html#579">LWG
issue #579</a>, this problem has been fixed while maintaining the interface of
<code>erase</code>, at the expense of using one more
word of memory per element. In fact, C++ complexity requirements on unordered
associative containers have been improved for hashed indices so that
<ul>
<li>deletion of a given element is unconditionally constant-time,</li>
<li>worst-case performance is not <code>O(n)</code> but <code>O(n<sub>dist</sub>)</code>,
where <code>n<sub>dist</sub></code> is the number of non-equivalent elements in the index.
</li>
</ul>
Due to the fact that hashed indices rely on a new data structure, the internal representation of
their iterators and local iterators have changed, which affects serialization: their corresponding
serialization <a href="../../serialization/doc/tutorial.html#versioning">class version</a> has been
bumped from 0 to 1. Old archives involving hashed index (local) iterators can be loaded
by Boost 1.56 version of Boost.MultiIndex, but not the other way around.
</li>
<li>Hashed indices now provide <code>reserve</code>.</li>
<li>Hashed indices can now be checked for equality and inequality following the
(suitably adapted) C++ standard specification in <b>[unord.req]</b>.</li>
<li>The public interface of Boost.MultiIndex provide <code>noexcept</code> specifications
where appropriate (for compliant compilers).
</li>
<li>Improved performance of failed insertions into a <code>multi_index_container</code>.</li>
<li>Much internal code aimed at supporting MSVC++ 7.0 and prior has been removed.
Compilation times without this legacy code might be slightly faster.
</li>
<li>Fixed a bug with insertion via iterators dereferencing to rvalues
(ticket <a href="https://svn.boost.org/trac/boost/ticket/9665">#9665</a>).
</li>
<li>Made Boost.MultiIndex compatible with <code>BOOST_BIND_NO_PLACEHOLDERS</code>
(ticket <a href="https://svn.boost.org/trac/boost/ticket/9798">#9798</a>).
</li>
<li>Maintenance fixes.</li>
</ul>
</p>
<h2><a name="boost_1_55">Boost 1.55 release</a></h2>
<p>
<ul>
<li>Boost.MultiIndex has been brought to a higher level of compliance
with C++11.
<ul>
<li><code>multi_index_container</code> is now efficiently movable.</li>
<li>Initializer lists supported.</li>
<li>Emplace functions provided.</li>
<li>Non-copyable elements (such as <code>std::unique_ptr&lt;T&gt;</code>) supported. This includes
insertion of a range [<code>first</code>,<code>last</code>) where the iterators point to a type that is
convertible to that of the element: no copy construction happens in the process.
</li>
<li>Random access indices provide <code>shrink_to_fit()</code>.</li>
</ul>
Refer to the <a href="compiler_specifics.html">compiler specifics</a> section for limitations
on pre-C++11 compilers.
</li>
<li>The following classes are deprecated:
<ul>
<li><a href="reference/key_extraction.html#member_offset"><code>member_offset</code></a>,</li>
<li><a href="reference/key_extraction.html#const_mem_fun_explicit"><code>const_mem_fun_explicit</code></a>,</li>
<li><a href="reference/key_extraction.html#const_mem_fun_explicit"><code>mem_fun_explicit</code></a>,</li>
<li><a href="reference/key_extraction.html#composite_key_result_equal_to"><code>composite_key_result_equal_to</code></a>,</li>
<li><a href="reference/key_extraction.html#composite_key_result_less"><code>composite_key_result_less</code></a>,</li>
<li><a href="reference/key_extraction.html#composite_key_result_greater"><code>composite_key_result_greater</code></a>,</li>
<li><a href="reference/key_extraction.html#composite_key_result_hash"><code>composite_key_result_hash</code></a>.</li>
</ul>
</li>
<li>Maintenance fixes.</li>
</ul>
</p>
<h2><a name="boost_1_54">Boost 1.54 release</a></h2>
<p>
<ul>
<li>Suppressed some potential warnings described in
tickets <a href="https://svn.boost.org/trac/boost/ticket/8034">#8034</a> and <a href="https://svn.boost.org/trac/boost/ticket/8129">#8129</a>.
</li>
<li>Maintenance fixes.</li>
</ul>
</p>
<h2><a name="boost_1_49">Boost 1.49 release</a></h2>
<p>
<ul>
<li>Suppressed a potential narrow conversion warning described in
ticket <a href="https://svn.boost.org/trac/boost/ticket/3365">#3365</a>.
</li>
</ul>
</p>
<h2><a name="boost_1_48">Boost 1.48 release</a></h2>
<p>
<ul>
<li>Fixed a compatibility problem with
<a href="../../../doc/html/foreach.html">Boost.Foreach</a>
(ticket <a href="https://svn.boost.org/trac/boost/ticket/5741">#5741</a>).
</li>
</ul>
</p>
<h2><a name="boost_1_47">Boost 1.47 release</a></h2>
<p>
<ul>
<li>Fixed an ADL problem in
<a href="reference/key_extraction.html#composite_key_compare"><code>composite_key_compare</code></a>
related with <a href="../../../doc/html/ref.html">Boost.Ref</a>.
</li>
<li>Maintenance fixes.</li>
</ul>
</p>
<h2><a name="boost_1_44">Boost 1.44 release</a></h2>
<p>
<ul>
<li>
Fixed a bug preventing the use of <code>modify_key</code> with
rollback in <a href="reference/ord_indices.html#modify_key">ordered</a> and
<a href="reference/hash_indices.html#modify_key">hashed</a> indices when
<code>Modifier</code> and <code>Rollback</code> are different types
(ticket <a href="https://svn.boost.org/trac/boost/ticket/4130">#4130</a>).
</li>
</ul>
</p>
<h2><a name="boost_1_43">Boost 1.43 release</a></h2>
<p>
<ul>
<li>
<a href="../../serialization/doc/serialization.html#constructors">Serialization
of non default constructible values</a> is now properly supported
through user-provided facilities <code>save_construct_data</code> and
<code>load_construct_data</code>.
<code>multi_index_container</code> serialization
<a href="../../serialization/doc/tutorial.html#versioning">class version</a> has been
bumped from 1 to 2.
</li>
</ul>
</p>
<h2><a name="boost_1_42">Boost 1.42 release</a></h2>
<p>
<ul>
<li>Maintenance fixes.</li>
</ul>
</p>
<h2><a name="boost_1_41">Boost 1.41 release</a></h2>
<p>
<ul>
<li>Serialization now uses the portable
<a href="../../serialization/doc/wrappers.html#collection_size_type"><code>collection_size_type</code></a>
type instead of the original <code>std::size_t</code> (ticket
<a href="https://svn.boost.org/trac/boost/ticket/3365">#3365</a>).
<code>multi_index_container</code> serialization
<a href="../../serialization/doc/tutorial.html#versioning">class version</a> has been
bumped from 0 to 1.
</li>
<li>Fixed a concurrency bug in the implementation of
<a href="tutorial/debug.html#safe_mode">safe mode</a>
(ticket <a href="https://svn.boost.org/trac/boost/ticket/3462">#3462</a>).
</li>
</ul>
</p>
<h2><a name="boost_1_38">Boost 1.38 release</a></h2>
<p>
<ul>
<li>These constructs are deprecated:
<ul>
<li><code>nth_index_iterator&lt;MultiIndexContainer,N&gt;::type</code>,</li>
<li><code>multi_index_container&lt;...&gt;::nth_index_iterator&lt;N&gt;::type</code>,</li>
<li><code>nth_index_const_iterator&lt;MultiIndexContainer,N&gt;::type</code>,</li>
<li><code>multi_index_container&lt;...&gt;::nth_index_const_iterator&lt;N&gt;::type</code>,</li>
<li><code>index_iterator&lt;MultiIndexContainer,Tag&gt;::type</code>,</li>
<li><code>multi_index_container&lt;...&gt;::index_iterator&lt;Tag&gt;::type</code>,</li>
<li><code>index_const_iterator&lt;MultiIndexContainer,Tag&gt;::type</code>,</li>
<li><code>multi_index_container&lt;...&gt;::index_const_iterator&lt;Tag&gt;::type</code>.</li>
</ul>
Use the following instead:
<ul>
<li><code>nth_index&lt;MultiIndexContainer,N&gt;::type::iterator</code>,</li>
<li><code>multi_index_container&lt;...&gt;::nth_index&lt;N&gt;::type::iterator</code>,</li>
<li><code>nth_index&lt;MultiIndexContainer,N&gt;::type::const_iterator</code>,</li>
<li><code>multi_index_container&lt;...&gt;::nth_index&lt;N&gt;::type::const_iterator</code>,</li>
<li><code>index&lt;MultiIndexContainer,Tag&gt;::type::iterator</code>,</li>
<li><code>multi_index_container&lt;...&gt;::index&lt;Tag&gt;::type::iterator</code>,</li>
<li><code>index&lt;MultiIndexContainer,Tag&gt;::type::const_iterator</code>,</li>
<li><code>multi_index_container&lt;...&gt;::index&lt;Tag&gt;::type::const_iterator</code>.</li>
</ul>
</li>
<li>Maintenance fixes.</li>
</ul>
</p>
<h2><a name="boost_1_37">Boost 1.37 release</a></h2>
<p>
<ul>
<li>Maintenance fixes.</li>
</ul>
</p>
<h2><a name="boost_1_36">Boost 1.36 release</a></h2>
<p>
<ul>
<li><a name="stable_update">On prior versions of the library, the <a href="tutorial/indices.html#hash_updating">update
member functions</a> of hashed indices could alter the position of an element even if the
associated key did not change with the update. This is legal but probably unexpected behavior.
The functions have been rewritten to provide the additional guarantee that elements with
unmodified key will not change position in hashed indices, just as always was the case with
ordered indices. These guarantees are now documented in the reference.</a></li>
<li>Added the constructor <code>multi_index_container::multi_index_container(const allocator_type&amp;)</code>
to mimic the equivalent interface in STL sequence containers.
<li>Maintenance fixes.</li>
</ul>
</p>
<h2><a name="boost_1_35">Boost 1.35 release</a></h2>
<p>
<ul>
<li>New <a href="tutorial/key_extraction.html#global_fun"><code>global_fun</code></a>
predefined key extractor.
</li>
<li>Added <a href="tutorial/indices.html#iterator_to"><code>iterator_to</code></a>
facility.
</li>
<li>Included <a href="tutorial/creation.html#special_allocator">support for
non-standard allocators</a> such as those of
<a href="../../interprocess/index.html">Boost.Interprocess</a>, which makes
<code>multi_index_container</code>s placeable in shared memory.
</li>
<li>New versions of <code>modify</code> and <code>modify_key</code> with
rollback, as described in the
<a href="tutorial/basics.html#ord_updating">tutorial</a>.
</li>
<li>Indices provide the new <code>cbegin</code>, <code>cend</code> and,
when applicable, <code>crbegin</code> and <code>crend</code>
member functions, in accordance with the latest drafts of the next
revision of the C++ standard.
</li>
<li>Hinted insertion in ordered indices fully conforms to the resolutions of
C++ Standard Library
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#233">Defect
Report 233</a>. The new requirement that the point of insertion
be always as close as possible to the hint induces a different behavior than
exhibited in former releases of Boost.MultiIndex, which can potentially cause
backwards compatibility problems; in any case, the likelihood of these
compatibility issues arising in a real scenario is very low.
</li>
<li>Sequenced and random access indices now follow the requirements of the
C++ standard for sequence containers with respect to the operations
<code>assign(f,l)</code> and <code>insert(p,f,l)</code> (23.1.1/9): if
<code>f</code> and <code>l</code> are of the same integral type, the
iterator-based overloads of these member functions are avoided:
<blockquote><pre>
<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special>&lt;</span>
<span class=keyword>int</span><span class=special>,</span><span class=identifier>indexed_by</span><span class=special>&lt;</span><span class=identifier>sequenced</span><span class=special>&lt;&gt;</span> <span class=special>&gt;</span>
<span class=special>&gt;</span> <span class=identifier>sequenced_container</span><span class=special>;</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>list</span><span class=special>&lt;</span><span class=keyword>int</span><span class=special>&gt;</span> <span class=identifier>l</span><span class=special>(...);</span>
<span class=identifier>sequenced_container</span> <span class=identifier>c</span><span class=special>;</span>
<span class=comment>// iterator-based overload of assign</span>
<span class=identifier>c</span><span class=special>.</span><span class=identifier>assign</span><span class=special>(</span><span class=identifier>l</span><span class=special>.</span><span class=identifier>begin</span><span class=special>(),</span><span class=identifier>l</span><span class=special>.</span><span class=identifier>end</span><span class=special>());</span>
<span class=comment>// The following is equivalent to
// c.assign(
// static_cast&lt;sequenced_container::size_type&gt;(10),100);
// that is, &quot;10&quot; and &quot;100&quot; are not taken to be iterators as
// in the previous expression.</span>
<span class=identifier>c</span><span class=special>.</span><span class=identifier>assign</span><span class=special>(</span><span class=number>10</span><span class=special>,</span><span class=number>100</span><span class=special>);</span>
</pre></blockquote>
</li>
<li>The performance of ordered indices <code>range</code> and
<code>equal_range</code> has been improved.
</li>
<li>Maintenance fixes.</li>
</ul>
</p>
<h2><a name="boost_1_34">Boost 1.34 release</a></h2>
<p>
<ul>
<li>Added <a href="tutorial/indices.html#rnd_indices">random access
indices</a>.
</li>
<li>Non key-based indices provide new
<a href="tutorial/indices.html#rearrange">rearrange facilities</a>
allowing for interaction with external mutating algorithms.
</li>
<li>All predefined Boost.MultiIndex key extractors
instantiated for a given type <code>T</code> can handle objects of types
derived from or convertible to <code>T</code> (and
<a href="reference/key_extraction.html#chained_pointers">chained pointers</a>
to those). Previously, only objects of the exact type specified (along with
<code>reference_wrapper</code>s and chained pointers to them) were accepted.
</li>
<li><a href="reference/key_extraction.html#composite_key_compare"><code>composite_key_compare</code></a>
and related classes accept operands not included in tuples as if they were passed
in a tuple of length 1; this allows the user to omit tuple enclosing in
lookup operations involving composite keys when only the first key is provided.
</li>
<li>The core algorithms of ordered indices have been optimized, yielding
an estimated reduction of about 5% in insertion times.
</li>
<li>Size of ordered indices node headers have been reduced by 25% on
most platforms, using a well known
<a href="tutorial/indices.html#ordered_node_compression">optimization
technique</a>.
</li>
<li>The tutorial has been restructured, new examples added.</li>
<li>Maintenance fixes.</li>
</ul>
</p>
<h2><a name="boost_1_33_1">Boost 1.33.1 release</a></h2>
<p>
<ul>
<li>For ordered and hashed indices, <code>erase(it)</code> and
<code>erase(first,last)</code> now return an iterator to the element
following those being deleted (previously nothing was returned), in
accordance with the C++ Standard Library
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#130">Defect
Report 130</a> and issue 6.19 of TR1
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1837.pdf">Issues
List</a>.
</li>
<li>Boost.MultiIndex offers the usual guarantees with respect to
multithreading code provided by most STL implementations:
<ol>
<li>Concurrent access to different containers is safe.</li>
<li>Concurrent read-only access to the same container is safe.</li>
</ol>
In previous versions of the library, the latter guarantee was not properly
maintained if the <a href="tutorial/debug.html#safe_mode">safe
mode</a> was set. This problem has been fixed now.
</li>
<li>Maintenance fixes.</li>
</ul>
</p>
<h2><a name="boost_1_33">Boost 1.33 release</a></h2>
<p>
<ul>
<li>Added <a href="tutorial/indices.html#hashed_indices">hashed indices</a>,
whose interface is based on the specification for unordered associative
containers by the C++ Standard Library Technical Report (TR1).
</li>
<li>Added <a href="tutorial/creation.html#serialization">serialization support</a>
for <a href="../../serialization/index.html">Boost.Serialization</a>.
</li>
<li>Destruction of <code>multi_index_container</code>s and <code>clear</code>
memfuns now perform faster.
</li>
<li>Internal changes aimed at reducing the length of symbol names generated
by the compiler; cuts of up to a 50% can be achieved with respect to the
Boost 1.32 release. This results in much shorter and more readable error
messages and has also a beneficial impact on compilers with strict limits on
symbol name lengths. Additionally, a section on further
<a href="compiler_specifics.html#symbol_reduction">reduction of symbol name
lengths</a> has been added.
</li>
<li>Restructured some parts of the documentation, new examples.</li>
<li>Maintenance fixes.</li>
</ul>
</p>
<hr>
<div class="prev_link"><a href="future_work.html"><img src="prev.gif" alt="future work" border="0"><br>
Future work
</a></div>
<div class="up_link"><a href="index.html"><img src="up.gif" alt="index" border="0"><br>
Index
</a></div>
<div class="next_link"><a href="acknowledgements.html"><img src="next.gif" alt="acknowledgements" border="0"><br>
Acknowledgements
</a></div><br clear="all" style="clear: all;">
<br>
<p>Revised September 21st 2017</p>
<p>&copy; Copyright 2003-2017 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz.
Distributed under the Boost Software
License, Version 1.0. (See accompanying file <a href="../../../LICENSE_1_0.txt">
LICENSE_1_0.txt</a> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">
http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</body>
</html>

View File

@@ -0,0 +1,54 @@
/* Copyright 2003-2004 Joaqu<71>n M L<>pez Mu<4D>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)
*/
pre{
BORDER-RIGHT: gray 1pt solid;
PADDING-RIGHT: 2pt;
BORDER-TOP: gray 1pt solid;
DISPLAY: block;
PADDING-LEFT: 2pt;
PADDING-BOTTOM: 2pt;
BORDER-LEFT: gray 1pt solid;
MARGIN-RIGHT: 32pt;
PADDING-TOP: 2pt;
BORDER-BOTTOM: gray 1pt solid;
FONT-FAMILY: "Courier New", Courier, mono;
background-color: #EEEEEE;
}
table{
PADDING-RIGHT: 2pt;
BORDER-TOP: gray 1pt solid;
DISPLAY: block;
PADDING-LEFT: 2pt;
PADDING-BOTTOM: 2pt;
BORDER-LEFT: gray 1pt solid;
MARGIN-RIGHT: 32pt;
PADDING-TOP: 2pt;
background-color: #EEEEEE;
}
td{
BORDER-STYLE: solid;
BORDER-WIDTH: 1pt;
BORDER-LEFT: ;
BORDER-RIGHT: gray 1pt solid;
BORDER-TOP: ;
BORDER-BOTTOM: gray 1pt solid;
}
th{color: #ffffff; background-color: #000000;}
.odd_tr{background-color: #ffffff;}
.keyword{color: #0000FF;}
.identifier{}
.comment{font-style: italic; color: #008000;}
.special{color: #800040;}
.preprocessor{color: #3F007F;}
.string{font-style: italic; color: #666666;}
.literal{font-style: italic; color: #666666;}
.prev_link{width: 30%; float: left; text-align: left;}
.up_link{width: 39.9%; float: left; text-align: center;}
.next_link{width: 30%; float: left; text-align: right;}

View File

@@ -0,0 +1,167 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0.1 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Boost.MultiIndex Documentation - Tests</title>
<link rel="stylesheet" href="style.css" type="text/css">
<link rel="start" href="index.html">
<link rel="prev" href="examples.html">
<link rel="up" href="index.html">
<link rel="next" href="future_work.html">
</head>
<body>
<h1><img src="../../../boost.png" alt="boost.png (6897 bytes)" align=
"middle" width="277" height="86">Boost.MultiIndex Tests</h1>
<div class="prev_link"><a href="examples.html"><img src="prev.gif" alt="examples" border="0"><br>
Examples
</a></div>
<div class="up_link"><a href="index.html"><img src="up.gif" alt="index" border="0"><br>
Index
</a></div>
<div class="next_link"><a href="future_work.html"><img src="next.gif" alt="future work" border="0"><br>
Future work
</a></div><br clear="all" style="clear: all;">
<hr>
<p>
The Boost.MultiIndex test suite exercises the whole spectrum of
functionalities provided by the library. Although the tests are not meant
to serve as a learning guide, the interested reader may find it
useful to inspect the source code to gain familiarity
with some of the least common features offered by Boost.MultiIndex.
</p>
<p align="center">
<table cellspacing="0" cellpadding="5">
<caption><b>Boost.MultiIndex test suite.</b></caption>
<tr>
<th>Program</th>
<th>Description</th>
</tr>
<tr>
<td><a href="../test/test_basic.cpp"><code>test_basic.cpp</code></a></td>
<td>Simple program along the lines of the employees example studied in the
tutorial.</td>
</tr>
<tr class="odd_tr">
<td><a href="../test/test_capacity.cpp"><code>test_capacity.cpp</code></a></td>
<td><code>empty</code>, <code>size</code>, <code>resize</code>
(non key-based indices) and <code>reserve</code>/<code>capacity</code>
(random access indices only).</td>
</tr>
<tr>
<td><a href="../test/test_comparison.cpp"><code>test_comparison.cpp</code></a></td>
<td>Comparison between indices.</td>
</tr>
<tr class="odd_tr">
<td><a href="../test/test_composite_key.cpp"><code>test_composite_key.cpp</code></a></td>
<td><code>composite_key</code> and <code>composite_key_compare</code>.</td>
</tr>
<tr>
<td><a href="../test/test_conv_iterators.cpp"><code>test_conv_iterators.cpp</code></a></td>
<td>Checks convertibility of non-constant to constant iterators.</td>
</tr>
<tr class="odd_tr">
<td><a href="../test/test_copy_assignment.cpp"><code>test_copy_assignment.cpp</code></a></td>
<td>Various forms of assignment: copy, <code>operator =</code>, insertion,
(non key-based indices only) <code>assign</code> .
</tr>
<tr>
<td><a href="../test/test_hash_ops.cpp"><code>test_hash_ops.cpp</code></a></td>
<td>Hashing operations.</td>
</tr>
<tr class="odd_tr">
<td><a href="../test/test_iterators.cpp"><code>test_iterators.cpp</code></a></td>
<td>Constant and non-constant iterators and their reverse variants.</td>
</tr>
<tr>
<td><a href="../test/test_key_extractors.cpp"><code>test_key_extractors.cpp</code></a></td>
<td>Covers all use cases of key extractors shipped with the library.</td>
</tr>
<tr class="odd_tr">
<td><a href="../test/test_list_ops.cpp"><code>test_list_ops.cpp</code></a></td>
<td>List-like operations particular to sequenced and random access indices.</td>
</tr>
<tr>
<td><a href="../test/test_modifiers.cpp"><code>test_modifiers.cpp</code></a></td>
<td>Checks the family of insertion and erasing operations.</td>
</tr>
<tr class="odd_tr">
<td><a href="../test/test_mpl_ops.cpp"><code>test_mpl_ops.cpp</code></a></td>
<td>Metaprogramming manipulations of <code>multi_index_container</code> types.</td>
</tr>
<tr>
<td><a href="../test/test_observers.cpp"><code>test_observers.cpp</code></a></td>
<td>Checks observer member functions of ordered and hashed indices.</td>
</tr>
<tr class="odd_tr">
<td><a href="../test/test_projection.cpp"><code>test_projection.cpp</code></a></td>
<td>Projection of iterators among indices.</td>
</tr>
<tr>
<td><a href="../test/test_range.cpp"><code>test_range.cpp</code></a></td>
<td>Exercises the <code>range</code> facility (ordered indices only).</td>
</tr>
<tr class="odd_tr">
<td><a href="../test/test_rank_ops.cpp"><code>test_rank_ops.cpp</code></a></td>
<td>Specific operations of ranked indices.</td>
</tr>
<tr>
<td><a href="../test/test_rearrange.cpp"><code>test_rearrange.cpp</code></a></td>
<td>Rearrange functions of sequenced and random access indices.</td>
</tr>
<tr class="odd_tr">
<td><a href="../test/test_safe_mode.cpp"><code>test_safe_mode.cpp</code></a></td>
<td>Comprehensive coverage of all conditions checked in safe mode.</td>
</tr>
<tr>
<td><a href="../test/test_serialization1.cpp"><code>test_serialization1.cpp</code></a><br>
<a href="../test/test_serialization2.cpp"><code>test_serialization2.cpp</code></a><br>
<a href="../test/test_serialization3.cpp"><code>test_serialization3.cpp</code></a></td>
<td>Serialization support.</td>
</tr>
<tr class="odd_tr">
<td><a href="../test/test_set_ops.cpp"><code>test_set_ops.cpp</code></a></td>
<td>Set-like operations particular to ordered indices.</td>
</tr>
<tr>
<td><a href="../test/test_special_set_ops.cpp"><code>test_special_set_ops.cpp</code></a></td>
<td>Checks special lookup operations using compatible sorting criteria.</td>
</tr>
<tr class="odd_tr">
<td><a href="../test/test_update.cpp"><code>test_update.cpp</code></a></td>
<td><code>replace</code>, <code>modify</code> and <code>modify_key</code>.</td>
</tr>
</table>
</p>
<hr>
<div class="prev_link"><a href="examples.html"><img src="prev.gif" alt="examples" border="0"><br>
Examples
</a></div>
<div class="up_link"><a href="index.html"><img src="up.gif" alt="index" border="0"><br>
Index
</a></div>
<div class="next_link"><a href="future_work.html"><img src="next.gif" alt="future work" border="0"><br>
Future work
</a></div><br clear="all" style="clear: all;">
<br>
<p>Revised April 19th 2015</p>
<p>&copy; Copyright 2003-2015 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz.
Distributed under the Boost Software
License, Version 1.0. (See accompanying file <a href="../../../LICENSE_1_0.txt">
LICENSE_1_0.txt</a> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">
http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,353 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0.1 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Boost.MultiIndex Documentation - Tutorial - Container creation</title>
<link rel="stylesheet" href="../style.css" type="text/css">
<link rel="start" href="../index.html">
<link rel="prev" href="key_extraction.html">
<link rel="up" href="index.html">
<link rel="next" href="debug.html">
</head>
<body>
<h1><img src="../../../../boost.png" alt="boost.png (6897 bytes)" align=
"middle" width="277" height="86">Boost.MultiIndex Tutorial: Container creation</h1>
<div class="prev_link"><a href="key_extraction.html"><img src="../prev.gif" alt="key extraction" border="0"><br>
Key extraction
</a></div>
<div class="up_link"><a href="index.html"><img src="../up.gif" alt="Boost.MultiIndex tutorial" border="0"><br>
Boost.MultiIndex tutorial
</a></div>
<div class="next_link"><a href="debug.html"><img src="../next.gif" alt="debugging support" border="0"><br>
Debugging support
</a></div><br clear="all" style="clear: all;">
<hr>
<h2>Contents</h2>
<ul>
<li><a href="#value_semantics">Value semantics</a></li>
<li><a href="#ctor_args_list">Use of <code>ctor_args_list</code></a></li>
<li><a href="#special_allocator">Special allocator support</a></li>
<li><a href="#serialization">Serialization</a></li>
</ul>
<h2><a name="value_semantics">Value semantics</a></h2>
<p>
<code>multi_index_container</code>s have the usual value semantics associated
to copy construction and assignment, i.e. copies of the elements from the source
container are created and inserted into the destination container.
More interestingly, copying also recreates the original order in which
elements are arranged for <i>every index</i> of the container.
This implies that equality of all indices is preserved under copying
or assignment, for those index types where equality is defined. This behavior
can be regarded as a natural extension to the general rule on copy semantics
stating that if <code>y</code> is a copy of <code>x</code>, then
<code>y==x</code>.
</p>
<h2><a name="ctor_args_list">Use of <code>ctor_args_list</code></a></h2>
<p>
Although in most cases <code>multi_index_container</code>s will be default constructed
(or copied from a preexisting <code>multi_index_container</code>), sometimes it is
necessary to specify particular values for the internal objects used (key extractors,
comparison predicates, allocator), for instance if some of these objects do not have
a default constructor. The same situation can arise with standard STL containers,
which allow for the optional specification of such objects:
</p>
<blockquote><pre>
<span class=comment>// example of non-default constructed std::set</span>
<span class=keyword>template</span><span class=special>&lt;</span><span class=keyword>typename</span> <span class=identifier>IntegralType</span><span class=special>&gt;</span>
<span class=keyword>struct</span> <span class=identifier>modulo_less</span>
<span class=special>{</span>
<span class=identifier>modulo_less</span><span class=special>(</span><span class=identifier>IntegralType</span> <span class=identifier>m</span><span class=special>):</span><span class=identifier>modulo</span><span class=special>(</span><span class=identifier>m</span><span class=special>){}</span>
<span class=keyword>bool</span> <span class=keyword>operator</span><span class=special>()(</span><span class=identifier>IntegralType</span> <span class=identifier>x</span><span class=special>,</span><span class=identifier>IntegralType</span> <span class=identifier>y</span><span class=special>)</span><span class=keyword>const</span>
<span class=special>{</span>
<span class=keyword>return</span> <span class=special>(</span><span class=identifier>x</span><span class=special>%</span><span class=identifier>modulo</span><span class=special>)&lt;(</span><span class=identifier>y</span><span class=special>%</span><span class=identifier>modulo</span><span class=special>);</span>
<span class=special>}</span>
<span class=keyword>private</span><span class=special>:</span>
<span class=identifier>IntegralType</span> <span class=identifier>modulo</span><span class=special>;</span>
<span class=special>};</span>
<span class=keyword>typedef</span> <span class=identifier>std</span><span class=special>::</span><span class=identifier>set</span><span class=special>&lt;</span><span class=keyword>unsigned</span> <span class=keyword>int</span><span class=special>,</span><span class=identifier>modulo_less</span><span class=special>&lt;</span><span class=keyword>unsigned</span> <span class=keyword>int</span><span class=special>&gt;</span> <span class=special>&gt;</span> <span class=identifier>modulo_set</span><span class=special>;</span>
<span class=identifier>modulo_set</span> <span class=identifier>m</span><span class=special>(</span><span class=identifier>modulo_less</span><span class=special>&lt;</span><span class=keyword>unsigned</span> <span class=keyword>int</span><span class=special>&gt;(</span><span class=number>10</span><span class=special>));</span>
</pre></blockquote>
<p>
<code>multi_index_container</code> does also provide this functionality, though in a
considerably more complex fashion, due to the fact that the constructor
of a <code>multi_index_container</code> has to accept values for all the internal
objects of its indices. The full form of <code>multi_index_container</code> constructor
is
</p>
<blockquote><pre>
<span class=keyword>explicit</span> <span class=identifier>multi_index_container</span><span class=special>(</span>
<span class=keyword>const</span> <span class=identifier>ctor_args_list</span><span class=special>&amp;</span> <span class=identifier>args_list</span><span class=special>=</span><span class=identifier>ctor_args_list</span><span class=special>(),</span>
<span class=keyword>const</span> <span class=identifier>allocator_type</span><span class=special>&amp;</span> <span class=identifier>al</span><span class=special>=</span><span class=identifier>allocator_type</span><span class=special>());</span>
</pre></blockquote>
<p>
The specification of the allocator object poses no particular problems;
as for the <code>ctor_args_list</code>, this object is designed so as to hold
the necessary construction values for every index in the <code>multi_index_container</code>.
From the point of view of the user, <code>ctor_args_list</code> is equivalent
to the type
</p>
<blockquote><pre>
<span class=identifier>boost</span><span class=special>::</span><span class=identifier>tuple</span><span class=special>&lt;</span><span class=identifier>C<sub>0</sub></span><span class=special>,...,</span><span class=identifier>C<sub>I-1</sub></span><span class=special>&gt;</span>
</pre></blockquote>
<p>
where <code>I</code> is the number of indices, and <code>C<sub>i</sub></code> is
</p>
<blockquote><pre>
<span class=identifier>nth_index</span><span class=special>&lt;</span><span class=identifier>i</span><span class=special>&gt;::</span><span class=identifier>type</span><span class=special>::</span><span class=identifier>ctor_args</span>
</pre></blockquote>
<p>
that is, the nested type <code>ctor_args</code> of the <code>i</code>-th index. Each
<code>ctor_args</code> type is in turn a tuple holding values for constructor
arguments of the associated index: so, ordered indices demand a key extractor object
and a comparison predicate, hashed indices take an initial number of buckets,
a key extractor, a hash function and an equality predicate; while sequenced
and random access indices do not need any construction argument. For instance,
given the definition
</p>
<blockquote><pre>
<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special>&lt;</span>
<span class=keyword>unsigned</span> <span class=keyword>int</span><span class=special>,</span>
<span class=identifier>indexed_by</span><span class=special>&lt;</span>
<span class=identifier>hashed_unique</span><span class=special>&lt;</span><span class=identifier>identity</span><span class=special>&lt;</span><span class=keyword>unsigned</span> <span class=keyword>int</span><span class=special>&gt;</span> <span class=special>&gt;,</span>
<span class=identifier>ordered_non_unique</span><span class=special>&lt;</span><span class=identifier>identity</span><span class=special>&lt;</span><span class=keyword>unsigned</span> <span class=keyword>int</span><span class=special>&gt;,</span> <span class=identifier>modulo_less</span><span class=special>&lt;</span><span class=keyword>unsigned</span> <span class=keyword>int</span><span class=special>&gt;</span> <span class=special>&gt;,</span>
<span class=identifier>sequenced</span><span class=special>&lt;&gt;,</span>
<span class=identifier>random_access</span><span class=special>&lt;&gt;</span>
<span class=special>&gt;</span>
<span class=special>&gt;</span> <span class=identifier>modulo_indexed_set</span><span class=special>;</span>
</pre></blockquote>
<p>
the corresponding <code>ctor_args_list</code> type is equivalent to
</p>
<blockquote><pre>
<span class=identifier>boost</span><span class=special>::</span><span class=identifier>tuple</span><span class=special>&lt;</span>
<span class=comment>// ctr_args of index #0</span>
<span class=identifier>boost</span><span class=special>::</span><span class=identifier>tuple</span><span class=special>&lt;</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>size_t</span><span class=special>,</span> <span class=comment>// initial number of buckets; 0 if unspecified</span>
<span class=identifier>identity</span><span class=special>&lt;</span><span class=keyword>unsigned</span> <span class=keyword>int</span><span class=special>&gt;,</span>
<span class=identifier>boost</span><span class=special>::</span><span class=identifier>hash</span><span class=special>&lt;</span><span class=keyword>unsigned</span> <span class=keyword>int</span><span class=special>&gt;,</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>equal_to</span><span class=special>&lt;</span><span class=keyword>unsigned</span> <span class=keyword>int</span><span class=special>&gt;</span> <span class=special>&gt;,</span>
<span class=comment>// ctr_args of index #1</span>
<span class=identifier>boost</span><span class=special>::</span><span class=identifier>tuple</span><span class=special>&lt;</span>
<span class=identifier>identity</span><span class=special>&lt;</span><span class=keyword>unsigned</span> <span class=keyword>int</span><span class=special>&gt;,</span>
<span class=identifier>modulo_less</span><span class=special>&lt;</span><span class=keyword>unsigned</span> <span class=keyword>int</span><span class=special>&gt;</span> <span class=special>&gt;,</span>
<span class=comment>// sequenced indices do not have any construction argument</span>
<span class=identifier>boost</span><span class=special>::</span><span class=identifier>tuple</span><span class=special>&lt;&gt;,</span>
<span class=comment>// neither do random access indices</span>
<span class=identifier>boost</span><span class=special>::</span><span class=identifier>tuple</span><span class=special>&lt;&gt;</span>
<span class=special>&gt;</span>
</pre></blockquote>
<p>
Such a <code>modulo_indexed_set</code> cannot be default constructed, because
<code>modulo_less</code> does not provide a default constructor. The following shows
how the construction can be done:
</p>
<blockquote><pre>
<span class=identifier>modulo_indexed_set</span><span class=special>::</span><span class=identifier>ctor_args_list</span> <span class=identifier>args_list</span><span class=special>=</span>
<span class=identifier>boost</span><span class=special>::</span><span class=identifier>make_tuple</span><span class=special>(</span>
<span class=comment>// ctor_args for index #0 is default constructible</span>
<span class=identifier>modulo_indexed_set</span><span class=special>::</span><span class=identifier>nth_index</span><span class=special>&lt;</span><span class=number>0</span><span class=special>&gt;::</span><span class=identifier>type</span><span class=special>::</span><span class=identifier>ctor_args</span><span class=special>(),</span>
<span class=identifier>boost</span><span class=special>::</span><span class=identifier>make_tuple</span><span class=special>(</span><span class=identifier>identity</span><span class=special>&lt;</span><span class=keyword>unsigned</span> <span class=keyword>int</span><span class=special>&gt;(),</span><span class=identifier>modulo_less</span><span class=special>&lt;</span><span class=keyword>unsigned</span> <span class=keyword>int</span><span class=special>&gt;(</span><span class=number>10</span><span class=special>)),</span>
<span class=comment>// these are also default constructible (actually, empty tuples)</span>
<span class=identifier>modulo_indexed_set</span><span class=special>::</span><span class=identifier>nth_index</span><span class=special>&lt;</span><span class=number>2</span><span class=special>&gt;::</span><span class=identifier>type</span><span class=special>::</span><span class=identifier>ctor_args</span><span class=special>(),</span>
<span class=identifier>modulo_indexed_set</span><span class=special>::</span><span class=identifier>nth_index</span><span class=special>&lt;</span><span class=number>3</span><span class=special>&gt;::</span><span class=identifier>type</span><span class=special>::</span><span class=identifier>ctor_args</span><span class=special>()</span>
<span class=special>);</span>
<span class=identifier>modulo_indexed_set</span> <span class=identifier>m</span><span class=special>(</span><span class=identifier>args_list</span><span class=special>);</span>
</pre></blockquote>
<p>
A program is provided in the <a href="../examples.html#example3">examples section</a> that
puts in practise these concepts.
</p>
<h2><a name="special_allocator">Special allocator support</a></h2>
<p>
Boost.MultiIndex allows for a slightly more general class of allocators
than strictly required by the C++ standard, as explained in detail in the
<a href="../reference/multi_index_container.html#instantiation_types">reference</a>.
An important type of non-standard allocators supported are those provided by the
<a href="../../../interprocess/index.html">Boost Interprocess Library</a>;
this opens up the possibility of placing <code>multi_index_container</code>s
in shared memory.
</p>
<blockquote><pre>
<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>interprocess</span><span class=special>/</span><span class=identifier>allocators</span><span class=special>/</span><span class=identifier>allocator</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>interprocess</span><span class=special>/</span><span class=identifier>managed_shared_memory</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
<span class=keyword>namespace</span> <span class=identifier>bip</span><span class=special>=</span><span class=identifier>boost</span><span class=special>::</span><span class=identifier>interprocess</span><span class=special>;</span>
<span class=comment>// a shared memory compatible allocator of ints</span>
<span class=keyword>typedef</span> <span class=identifier>bip</span><span class=special>::</span><span class=identifier>allocator</span><span class=special>&lt;</span>
<span class=keyword>int</span><span class=special>,</span><span class=identifier>bip</span><span class=special>::</span><span class=identifier>managed_shared_memory</span><span class=special>::</span><span class=identifier>segment_manager</span>
<span class=special>&gt;</span> <span class=identifier>shared_int_allocator</span><span class=special>;</span>
<span class=comment>// define a shared memory compatible multi_index_container
// using shared_int_allocator</span>
<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special>&lt;</span>
<span class=keyword>int</span><span class=special>,</span>
<span class=identifier>indexed_by</span><span class=special>&lt;</span>
<span class=identifier>sequenced</span><span class=special>&lt;&gt;,</span>
<span class=identifier>ordered_unique</span><span class=special>&lt;</span><span class=identifier>identity</span><span class=special>&lt;</span><span class=keyword>int</span><span class=special>&gt;</span> <span class=special>&gt;</span>
<span class=special>&gt;,</span>
<span class=identifier>shared_int_allocator</span>
<span class=special>&gt;</span> <span class=identifier>unique_int_list</span><span class=special>;</span>
<span class=special>...</span>
<span class=comment>// create a managed memory segment</span>
<span class=identifier>bip</span><span class=special>::</span><span class=identifier>managed_shared_memory</span> <span class=identifier>seg</span><span class=special>(</span>
<span class=identifier>bip</span><span class=special>::</span><span class=identifier>create_only</span><span class=special>,</span><span class=string>&quot;SharedMemoryID&quot;</span><span class=special>,</span><span class=number>65536</span><span class=special>);</span>
<span class=comment>// construct a unique_int_list into the segment</span>
<span class=identifier>unique_int_list</span><span class=special>*</span> <span class=identifier>puil</span><span class=special>=</span><span class=identifier>seg</span><span class=special>.</span><span class=identifier>construct</span><span class=special>&lt;</span><span class=identifier>unique_int_list</span><span class=special>&gt;</span>
<span class=special>(</span><span class=string>&quot;UniqueIntListID&quot;</span><span class=special>)</span> <span class=comment>// object identifier within the segment
// Construction args: first a ctor arg list, then a
// shared memory allocator obtained from the segment object.</span>
<span class=special>(</span><span class=identifier>unique_int_list</span><span class=special>::</span><span class=identifier>ctor_args_list</span><span class=special>(),</span>
<span class=identifier>unique_int_list</span><span class=special>::</span><span class=identifier>allocator_type</span><span class=special>(</span><span class=identifier>seg</span><span class=special>.</span><span class=identifier>get_segment_manager</span><span class=special>()));</span>
</pre></blockquote>
<p>
The examples section includes a <a href="../examples.html#example12">program</a>
that further explores this capability.
</p>
<h2><a name="serialization">Serialization</a></h2>
<p>
<code>multi_index_container</code>s can be archived and retrieved by means of the
<a href="../../../serialization/index.html">Boost Serialization Library</a>. Both regular
and XML archives are supported. The usage is straightforward and does not
differ from that of any other serializable type. For instance:
</p>
<blockquote><pre>
<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>archive</span><span class=special>/</span><span class=identifier>text_oarchive</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>archive</span><span class=special>/</span><span class=identifier>text_iarchive</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>fstream</span><span class=special>&gt;</span>
<span class=special>...</span>
<span class=keyword>void</span> <span class=identifier>save</span><span class=special>(</span><span class=keyword>const</span> <span class=identifier>employee_set</span><span class=special>&amp;</span> <span class=identifier>es</span><span class=special>)</span>
<span class=special>{</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>ofstream</span> <span class=identifier>ofs</span><span class=special>(</span><span class=string>&quot;data&quot;</span><span class=special>);</span>
<span class=identifier>boost</span><span class=special>::</span><span class=identifier>archive</span><span class=special>::</span><span class=identifier>text_oarchive</span> <span class=identifier>oa</span><span class=special>(</span><span class=identifier>ofs</span><span class=special>);</span>
<span class=identifier>oa</span><span class=special>&lt;&lt;</span><span class=identifier>es</span><span class=special>;</span>
<span class=special>}</span>
<span class=keyword>void</span> <span class=identifier>load</span><span class=special>(</span><span class=identifier>employee_set</span><span class=special>&amp;</span> <span class=identifier>es</span><span class=special>)</span>
<span class=special>{</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>ifstream</span> <span class=identifier>ifs</span><span class=special>(</span><span class=string>&quot;data&quot;</span><span class=special>);</span>
<span class=identifier>boost</span><span class=special>::</span><span class=identifier>archive</span><span class=special>::</span><span class=identifier>text_iarchive</span> <span class=identifier>ia</span><span class=special>(</span><span class=identifier>ifs</span><span class=special>);</span>
<span class=identifier>ia</span><span class=special>&gt;&gt;</span><span class=identifier>es</span><span class=special>;</span>
<span class=special>}</span>
<span class=special>...</span>
<span class=identifier>employee_set</span> <span class=identifier>es</span><span class=special>;</span>
<span class=special>...</span> <span class=comment>// fill it with data</span>
<span class=identifier>save</span><span class=special>(</span><span class=identifier>es</span><span class=special>);</span>
<span class=special>...</span>
<span class=identifier>employee_set</span> <span class=identifier>restored_es</span><span class=special>;</span>
<span class=identifier>load</span><span class=special>(</span><span class=identifier>restored_es</span><span class=special>);</span>
</pre></blockquote>
<p>
Serialization capabilities are automatically provided by just linking with
the appropriate Boost.Serialization library module: it is not necessary
to explicitly include any header from Boost.Serialization,
apart from those declaring the type of archive used in the process. If not used,
however, serialization support can be disabled by globally defining the macro
<code>BOOST_MULTI_INDEX_DISABLE_SERIALIZATION</code>. Disabling serialization
for Boost.MultiIndex can yield a small improvement in build times, and may
be necessary in those defective compilers that fail to correctly process
Boost.Serialization headers.
</p>
<p>
In accordance with Boost.MultiIndex
<a href="#value_semantics">value semantics</a>, retrieving an
archived <code>multi_index_container</code> restores not only
the elements, but also the order they were arranged into for
every index of the container. There is an exception to this rule,
though: for <a href="indices.html#hashed_indices">hashed
indices</a>, no guarantee is made about the order in which elements will
be iterated in the restored container; in general, it is unwise to rely on
the ordering of elements of a hashed index, since it can change in arbitrary
ways during insertion or rehashing --this is precisely the reason why
hashed indices and TR1 unordered associative containers do not define
an equality operator.
</p>
<p>
Iterators to indices of a <code>multi_index_container</code> can also be
serialized. Serialization of iterators must be done only after serializing
their corresponding container.
</p>
<p>
<a href="../examples.html#example9">Example 9</a> in the examples section shows
the serialization capabilities of Boost.MultiIndex.
</p>
<hr>
<div class="prev_link"><a href="key_extraction.html"><img src="../prev.gif" alt="key extraction" border="0"><br>
Key extraction
</a></div>
<div class="up_link"><a href="index.html"><img src="../up.gif" alt="Boost.MultiIndex tutorial" border="0"><br>
Boost.MultiIndex tutorial
</a></div>
<div class="next_link"><a href="debug.html"><img src="../next.gif" alt="debugging support" border="0"><br>
Debugging support
</a></div><br clear="all" style="clear: all;">
<br>
<p>Revised July 17th 2007</p>
<p>&copy; Copyright 2003-2007 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz.
Distributed under the Boost Software
License, Version 1.0. (See accompanying file <a href="../../../../LICENSE_1_0.txt">
LICENSE_1_0.txt</a> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">
http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</body>
</html>

View File

@@ -0,0 +1,252 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0.1 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Boost.MultiIndex Documentation - Tutorial -Debugging support</title>
<link rel="stylesheet" href="../style.css" type="text/css">
<link rel="start" href="../index.html">
<link rel="prev" href="creation.html">
<link rel="up" href="index.html">
<link rel="next" href="techniques.html">
</head>
<body>
<h1><img src="../../../../boost.png" alt="boost.png (6897 bytes)" align=
"middle" width="277" height="86">Boost.MultiIndex Tutorial: Debugging support</h1>
<div class="prev_link"><a href="creation.html"><img src="../prev.gif" alt="container creation" border="0"><br>
Container creation
</a></div>
<div class="up_link"><a href="index.html"><img src="../up.gif" alt="Boost.MultiIndex tutorial" border="0"><br>
Boost.MultiIndex tutorial
</a></div>
<div class="next_link"><a href="techniques.html"><img src="../next.gif" alt="techniques" border="0"><br>
Techniques
</a></div><br clear="all" style="clear: all;">
<hr>
<h2>Contents</h2>
<ul>
<li><a href="#debugging_support">Debugging support</a></li>
<li><a href="#safe_mode">Safe mode</a>
<ul>
<li><a href="#serialization_and_safe_mode">Serialization and safe mode</a></li>
</ul>
</li>
<li><a href="#invariant_check">Invariant-checking mode</a></li>
</ul>
<h2><a name="debugging_support">Debugging support</a></h2>
<p>
The concept of <i>Design by Contract</i>, originally developed as part
of Bertrand Meyer's <a href="http://www.eiffel.com">Eiffel</a> language,
revolves around the formulation of a <i>contract</i> between the user
of a library and the implementor, by which the first is required to
respect some <i>preconditions</i> on the values passed when invoking
methods of the library, and the implementor guarantees in return
that certain constraints on the results are met (<i>postconditions</i>),
as well as the honoring of specified internal consistency rules, called
<i>invariants</i>. Eiffel natively supports the three parts of the
contract just described by means of constructs <code>require</code>,
<code>ensure</code> and <code>invariant</code>, respectively.
</p>
<p>
C++ does not enjoy direct support for Design by Contract techniques: these
are customarily implemented as assertion code, often turned off in
release mode for performance reasons. Following this approach,
Boost.MultiIndex provides two distinct debugging modes:
<ul>
<li><i>Safe mode</i> checks preconditions on the invocations to the
facilities of the library,</li>
<li><i>invariant-checking mode</i> performs post-execution checks aimed
at ensuring that the internal consistency of the library is preserved.</li>
</ul>
These two modes are independent of each other and can be set on or off
individually. It is important to note that errors detected by safe mode are
due in principle to faulty code in the user's program, while
invariant-checking mode detects potential <i>internal</i> bugs in the
implementation of Boost.MultiIndex.
</p>
<h2><a name="safe_mode">Safe mode</a></h2>
<p>
The idea of adding precondition checking facilities to STL as a debugging aid
was first introduced by Cay S. Horstmann in his
<a href="http://www.horstmann.com/safestl.html">Safe STL</a> library and later
adopted by <a href="http://www.stlport.com/doc/debug_mode.html">STLport Debug
Mode</a>. Similarly, Boost.MultiIndex features the so-called <i>safe mode</i>
in which all sorts of preconditions are checked when dealing with iterators
and functions of the library.
</p>
<p>
Boost.MultiIndex safe mode is set by globally defining the macro
<code>BOOST_MULTI_INDEX_ENABLE_SAFE_MODE</code>. Error conditions
are checked via the macro <code>BOOST_MULTI_INDEX_SAFE_MODE_ASSERT</code>, which
by default resolves to a call to <a href="../../../../libs/assert">
<code>BOOST_ASSERT</code></a>.
</p>
<p>
If the user decides to define her own version of
<code>BOOST_MULTI_INDEX_SAFE_MODE_ASSERT</code>, it has to take the form
</p>
<blockquote><pre>
<span class=identifier>BOOST_MULTI_INDEX_SAFE_MODE_ASSERT</span><span class=special>(</span><span class=identifier>expr</span><span class=special>,</span><span class=identifier>error_code</span><span class=special>)</span>
</pre></blockquote>
<p>
where <code>expr</code> is the condition checked and <code>error_code</code>
is one value of the <code>safe_mode::error_code</code> enumeration:
</p>
<blockquote><pre>
<span class=keyword>namespace</span> <span class=identifier>boost</span><span class=special>{</span>
<span class=keyword>namespace</span> <span class=identifier>multi_index</span><span class=special>{</span>
<span class=keyword>namespace</span> <span class=identifier>safe_mode</span><span class=special>{</span>
<span class=keyword>enum</span> <span class=identifier>error_code</span>
<span class=special>{</span>
<span class=identifier>invalid_iterator</span><span class=special>,</span> <span class=comment>// vg. default cted or pointing to erased element</span>
<span class=identifier>not_dereferenceable_iterator</span><span class=special>,</span> <span class=comment>// iterator is not dereferenceable</span>
<span class=identifier>not_incrementable_iterator</span><span class=special>,</span> <span class=comment>// iterator points to end of sequence</span>
<span class=identifier>not_decrementable_iterator</span><span class=special>,</span> <span class=comment>// iterator points to beginning of sequence</span>
<span class=identifier>not_owner</span><span class=special>,</span> <span class=comment>// iterator does not belong to the container</span>
<span class=identifier>not_same_owner</span><span class=special>,</span> <span class=comment>// iterators belong to different containers</span>
<span class=identifier>invalid_range</span><span class=special>,</span> <span class=comment>// last not reachable from first</span>
<span class=identifier>inside_range</span><span class=special>,</span> <span class=comment>// iterator lies within a range (and it mustn't)</span>
<span class=identifier>out_of_bounds</span><span class=special>,</span> <span class=comment>// move attempted beyond container limits</span>
<span class=identifier>same_container</span> <span class=comment>// containers ought to be different</span>
<span class=special>};</span>
<span class=special>}</span> <span class=comment>// namespace multi_index::safe_mode</span>
<span class=special>}</span> <span class=comment>// namespace multi_index</span>
<span class=special>}</span> <span class=comment>// namespace boost</span>
</pre></blockquote>
<p>
For instance, the following replacement of
<code>BOOST_MULTI_INDEX_SAFE_MODE_ASSERT</code> throws an exception instead of
asserting:
</p>
<blockquote><pre>
<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>multi_index_container</span><span class=special>/</span><span class=identifier>safe_mode_errors</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
<span class=keyword>struct</span> <span class=identifier>safe_mode_exception</span>
<span class=special>{</span>
<span class=identifier>safe_mode_exception</span><span class=special>(</span><span class=identifier>boost</span><span class=special>::</span><span class=identifier>multi_index</span><span class=special>::</span><span class=identifier>safe_mode</span><span class=special>::</span><span class=identifier>error_code</span> <span class=identifier>error_code</span><span class=special>):</span>
<span class=identifier>error_code</span><span class=special>(</span><span class=identifier>error_code</span><span class=special>)</span>
<span class=special>{}</span>
<span class=identifier>boost</span><span class=special>::</span><span class=identifier>multi_index</span><span class=special>::</span><span class=identifier>safe_mode</span><span class=special>::</span><span class=identifier>error_code</span> <span class=identifier>error_code</span><span class=special>;</span>
<span class=special>};</span>
<span class=preprocessor>#define</span> <span class=identifier>BOOST_MULTI_INDEX_SAFE_MODE_ASSERT</span><span class=special>(</span><span class=identifier>expr</span><span class=special>,</span><span class=identifier>error_code</span><span class=special>)</span> <span class=special>\</span>
<span class=keyword>if</span><span class=special>(!(</span><span class=identifier>expr</span><span class=special>)){</span><span class=keyword>throw</span> <span class=identifier>safe_mode_exception</span><span class=special>(</span><span class=identifier>error_code</span><span class=special>);}</span>
<span class=comment>// This has to go before the inclusion of any header from Boost.MultiIndex,
// except possibly safe_error_codes.hpp.</span>
</pre></blockquote>
<p>
Other possibilites, like outputting to a log or firing some kind of alert, are
also implementable.
</p>
<p>
<b>Warning:</b> Safe mode adds a very important overhead to the program
both in terms of space and time used, so in general it should not be set for
<code>NDEBUG</code> builds. Also, this mode is intended solely as a debugging aid,
and programs must not rely on it as part of their normal execution flow: in
particular, no guarantee is made that all possible precondition errors are diagnosed,
or that the checks remain stable across different versions of the library.
</p>
<h3><a name="serialization_and_safe_mode">Serialization and safe mode</a></h3>
<p>
Iterators restored from an archive are not subject to safe mode checks. This is
so because it is not possible to automatically know the associated
<code>multi_index_container</code> of an iterator from the serialization
information alone. However, if desired, a restored iterator can be converted to a
checked value by using the following workaround:
</p>
<blockquote><pre>
<span class=identifier>employee_set</span> <span class=identifier>es</span><span class=special>;</span>
<span class=identifier>employee_set</span><span class=special>::</span><span class=identifier>nth_index</span><span class=special>&lt;</span><span class=number>1</span><span class=special>&gt;::</span><span class=identifier>iterator</span> <span class=identifier>it</span><span class=special>;</span>
<span class=comment>// restore es and it from an archive ar</span>
<span class=identifier>ar</span><span class=special>&gt;&gt;</span><span class=identifier>es</span><span class=special>;</span>
<span class=identifier>ar</span><span class=special>&gt;&gt;</span><span class=identifier>it</span><span class=special>;</span> <span class=comment>// it won't benefit from safe mode checks
// Turn it into a checked value by providing Boost.MultiIndex
// with info about the associated container.
// This statement has virtually zero cost if safe mode is turned off.</span>
<span class=identifier>it</span><span class=special>=</span><span class=identifier>es</span><span class=special>.</span><span class=identifier>project</span><span class=special>&lt;</span><span class=number>1</span><span class=special>&gt;(</span><span class=identifier>it</span><span class=special>);</span>
</pre></blockquote>
<h2><a name="invariant_check">Invariant-checking mode</a></h2>
<p>
The so called <i>invariant-checking mode</i> of Boost.MultiIndex can be
set by globally defining the macro
<code>BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING</code>.
When this mode is in effect, all public functions of Boost.MultiIndex
will perform post-execution tests aimed at ensuring that the basic
internal invariants of the data structures managed are preserved.
</p>
<p>
If an invariant test fails, Boost.MultiIndex will indicate the failure
by means of the unary macro <code>BOOST_MULTI_INDEX_INVARIANT_ASSERT</code>.
Unless the user provides a definition for this macro, it defaults to
<a href="../../../../libs/assert">
<code>BOOST_ASSERT</code></a>. Any assertion of this kind should
be regarded in principle as a bug in the library. Please report such
problems, along with as much contextual information as possible, to the
maintainer of the library.
</p>
<p>
It is recommended that users of Boost.MultiIndex always set the
invariant-checking mode in debug builds.
</p>
<hr>
<div class="prev_link"><a href="creation.html"><img src="../prev.gif" alt="container creation" border="0"><br>
Container creation
</a></div>
<div class="up_link"><a href="index.html"><img src="../up.gif" alt="Boost.MultiIndex tutorial" border="0"><br>
Boost.MultiIndex tutorial
</a></div>
<div class="next_link"><a href="techniques.html"><img src="../next.gif" alt="techniques" border="0"><br>
Techniques
</a></div><br clear="all" style="clear: all;">
<br>
<p>Revised July 07th 2017</p>
<p>&copy; Copyright 2003-2017 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz.
Distributed under the Boost Software
License, Version 1.0. (See accompanying file <a href="../../../../LICENSE_1_0.txt">
LICENSE_1_0.txt</a> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">
http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</body>
</html>

View File

@@ -0,0 +1,139 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0.1 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Boost.MultiIndex Documentation - Tutorial</title>
<link rel="stylesheet" href="../style.css" type="text/css">
<link rel="start" href="../index.html">
<link rel="prev" href="../index.html">
<link rel="up" href="../index.html">
<link rel="next" href="basics.html">
</head>
<body>
<h1><img src="../../../../boost.png" alt="boost.png (6897 bytes)" align=
"middle" width="277" height="86">Boost.MultiIndex Tutorial</h1>
<div class="prev_link"><a href="../index.html"><img src="../prev.gif" alt="index" border="0"><br>
Index
</a></div>
<div class="up_link"><a href="../index.html"><img src="../up.gif" alt="index" border="0"><br>
Index
</a></div>
<div class="next_link"><a href="basics.html"><img src="../next.gif" alt="basics" border="0"><br>
Basics
</a></div><br clear="all" style="clear: all;">
<hr>
<h2>Contents</h2>
<ul>
<li><a href="#rationale">Rationale</a></li>
<li><a href="#namespace">Namespace</a></li>
<li><a href="basics.html">Basics</a></li>
<li><a href="indices.html">Index types</a></li>
<li><a href="key_extraction.html">Key extraction</a></li>
<li><a href="creation.html">Container creation</a></li>
<li><a href="debug.html">Debugging support</a></li>
<li><a href="techniques.html">Techniques</a></li>
</ul>
<h2><a name="rationale">Rationale</a></h2>
<p>
STL containers are designed around the concept that each container controls its
own collection of elements, giving access to them in a manner specified by the
container's type: so, an <code>std::set</code> maintains the elements ordered
by a specified sorting criterion, <code>std::list</code> allows for free
positioning of elements along a linear sequence, and so on.
</p>
<p>
Sometimes, the necessity arises of having different access interfaces
to the same underlying collection: for instance, some data might need to be
sorted according to more than one comparison predicate, or a bidirectional list
might benefit from a supplemental logarithmic lookup interface. In these
situations, programmers typically resort to manual compositions of different
containers, a solution that generally involves a fair amount of code
devoted to preserve the synchronization of the different parts of
the composition. Boost.MultiIndex allows for the specification of
<code>multi_index_container</code>s comprised of one or more <i>indices</i> with
different interfaces to the same collection of elements. The resulting constructs
are conceptually cleaner than manual compositions, and often perform much better.
An important design decision has been taken that the indices of a given
<code>multi_index_container</code> instantiation be specified at compile time: this
gives ample room for static type checking and code optimization.
</p>
<p>
Boost.MultiIndex takes inspiration from basic concepts of indexing arising in the
theory of relational databases, though it is not intended to provide a full-fledged
relational database framework. <code>multi_index_container</code> integrates seamlessly
into the STL container/algorithm design, and features some extra capabilities regarding
lookup operations and element updating which are useful extensions even for
single-indexed containers.
</p>
<p align="center">
<img src="multi_index_cont_example.png"
alt="diagram of a multi_index_container with three indices"
width="600" height="304"><br>
<b>Fig. 1: Diagram of a <code>multi_index_container</code> with three indices.</b>
</p>
<p>
The figure above depicts a <code>multi_index_container</code> composed of three indices:
the first two present a set-like interface to the elements sorted by
shape and id, respectively, while the latter index provides the functionality
of a bidirectional list in the spirit of <code>std::list</code>. These
indices act as "views" to the internal collection of elements, but they do not only
provide read access to the set: insertion/deletion methods are also implemented much
as those of <code>std::set</code>s or <code>std::list</code>s. Insertion of an
element through one given index will only succeed if the uniqueness constraints of all
indices are met.
</p>
<h2>
<a name="namespace">Namespace</a>
</h2>
<p>
All the public types of Boost.MultiIndex reside in namespace <code>::boost::multi_index</code>.
Additionaly, the main class template <code>multi_index_container</code> and global functions
<code>get</code> and <code>project</code> are lifted to namespace <code>::boost</code>
by means of <code>using</code> declarations. For brevity of exposition, the fragments
of code in the documentation are written as if the following declarations were in effect:
</p>
<blockquote><pre>
<span class=keyword>using</span> <span class=keyword>namespace</span> <span class=special>::</span><span class=identifier>boost</span><span class=special>;</span>
<span class=keyword>using</span> <span class=keyword>namespace</span> <span class=special>::</span><span class=identifier>boost</span><span class=special>::</span><span class=identifier>multi_index</span><span class=special>;</span>
</pre></blockquote>
<hr>
<div class="prev_link"><a href="../index.html"><img src="../prev.gif" alt="index" border="0"><br>
Index
</a></div>
<div class="up_link"><a href="../index.html"><img src="../up.gif" alt="index" border="0"><br>
Index
</a></div>
<div class="next_link"><a href="basics.html"><img src="../next.gif" alt="basics" border="0"><br>
Basics
</a></div><br clear="all" style="clear: all;">
<br>
<p>Revised February 21st 2006</p>
<p>&copy; Copyright 2003-2006 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz.
Distributed under the Boost Software
License, Version 1.0. (See accompanying file <a href="../../../../LICENSE_1_0.txt">
LICENSE_1_0.txt</a> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">
http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</body>
</html>

View File

@@ -0,0 +1,834 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0.1 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Boost.MultiIndex Documentation - Tutorial - Index types</title>
<link rel="stylesheet" href="../style.css" type="text/css">
<link rel="start" href="../index.html">
<link rel="prev" href="basics.html">
<link rel="up" href="index.html">
<link rel="next" href="key_extraction.html">
</head>
<body>
<h1><img src="../../../../boost.png" alt="boost.png (6897 bytes)" align=
"middle" width="277" height="86">Boost.MultiIndex Tutorial: Index types</h1>
<div class="prev_link"><a href="basics.html"><img src="../prev.gif" alt="basics" border="0"><br>
Basics
</a></div>
<div class="up_link"><a href="index.html"><img src="../up.gif" alt="Boost.MultiIndex tutorial" border="0"><br>
Boost.MultiIndex tutorial
</a></div>
<div class="next_link"><a href="key_extraction.html"><img src="../next.gif" alt="key estraction" border="0"><br>
Key extraction
</a></div><br clear="all" style="clear: all;">
<hr>
<h2>Contents</h2>
<ul>
<li><a href="#classification">Classification</a>
<li><a href="#rnk_indices">Ranked indices</a>
<ul>
<li><a href="#rnk_spec">Specification</a></li>
<li><a href="#rnk_ops">Rank operations</a></li>
</ul>
</li>
<li><a href="#hashed_indices">Hashed indices</a>
<ul>
<li><a href="#hash_unique_non_unique">Unique and non-unique variants</a></li>
<li><a href="#hash_spec">Specification</a></li>
<li><a href="#hash_lookup">Lookup</a></li>
<li><a href="#hash_updating">Updating</a></li>
<li><a href="#guarantees">Guarantees on iterator validity and exception safety</a></li>
</ul>
</li>
<li><a href="#rnd_indices">Random access indices</a>
<ul>
<li><a href="#rnd_spec">Specification</a></li>
<li><a href="#rnd_interface">Interface</a></li>
<li><a href="#rnd_vs_vector">Comparison with <code>std::vector</code></a></li>
</ul>
</li>
<li><a href="#rearrange">Index rearranging</a></li>
<li><a href="#iterator_to"><code>iterator_to</code></a></li>
<li><a href="#ordered_node_compression">Ordered indices node compression</a></li>
</ul>
<h2><a name="classification">Classification</a></h2>
<p>
Boost.MultiIndex provides six different index types, which can be classified as
shown in the table below. <a href="basics.html#ord_indices">Ordered</a> and
<a href="basics.html#seq_indices">sequenced</a> indices,
which are the most commonly used, have been explained in the basics section;
the rest of index types can be regarded as variations of the former providing
some added benefits, functionally or in the area of performance.
</p>
<p align="center">
<table cellspacing="0">
<caption><b>Boost.MultiIndex indices.</b></caption>
<tr>
<th align="center"colspan="2">type</th>
<th align="center">specifier</th>
</tr>
<tr>
<td align="center" rowspan="6">&nbsp;&nbsp;key-based&nbsp;&nbsp;</td>
<td align="center" rowspan="4">&nbsp;&nbsp;ordered&nbsp;&nbsp;</td>
<td align="center">&nbsp;&nbsp;<code>ordered_unique</code>&nbsp;&nbsp;</td>
</tr>
<tr class="odd_tr">
<td align="center">&nbsp;&nbsp;<code>ordered_non_unique</code>&nbsp;&nbsp;</td>
</tr>
<tr>
<td align="center">&nbsp;&nbsp;<code>ranked_unique</code>&nbsp;&nbsp;</td>
</tr>
<tr class="odd_tr">
<td align="center">&nbsp;&nbsp;<code>ranked_non_unique</code>&nbsp;&nbsp;</td>
</tr>
<tr>
<td align="center" rowspan="2">&nbsp;&nbsp;hashed&nbsp;&nbsp;</td>
<td align="center">&nbsp;&nbsp;<code>hashed_unique</code>&nbsp;&nbsp;</td>
</tr>
<tr class="odd_tr">
<td align="center">&nbsp;&nbsp;<code>hashed_non_unique</code>&nbsp;&nbsp;</td>
</tr>
<tr>
<td align="center" rowspan="2" colspan="2">&nbsp;&nbsp;non key-based&nbsp;&nbsp;</td>
<td align="center"><code>&nbsp;&nbsp;sequenced&nbsp;&nbsp;</code></td>
</tr>
<tr class="odd_tr">
<td align="center"><code>&nbsp;&nbsp;random_access&nbsp;&nbsp;</code></td>
</tr>
</table>
</p>
<p>
Key-based indices, of which ordered indices are the usual example, provide
efficient lookup of elements based on some piece of information called the
<i>element key</i>: there is an extensive suite of
<a href="key_extraction.html">key extraction</a>
utility classes allowing for the specification of such keys. Fast lookup
imposes an internally managed order on these indices that the user is not
allowed to modify; non key-based indices, on the other hand, can be freely
rearranged at the expense of lacking lookup facilities. Sequenced indices,
modeled after the interface of <code>std::list</code>, are the customary
example of a non key-based index.
</p>
<h2><a name="rnk_indices">Ranked indices</a></h2>
<p>
Suppose we have a <code>std::multiset</code> of numbers and we want to output
the values above the 75h <a href="http://en.wikipedia.org/wiki/Percentile">percentile</a>:
</p>
<blockquote><pre>
<span class=keyword>typedef</span> <span class=identifier>std</span><span class=special>::</span><span class=identifier>multiset</span><span class=special>&lt;</span><span class=keyword>int</span><span class=special>&gt;</span> <span class=identifier>int_multiset</span><span class=special>;</span>
<span class=keyword>void</span> <span class=identifier>output_above_75th_percentile</span><span class=special>(</span><span class=keyword>const</span> <span class=identifier>int_multiset</span><span class=special>&amp;</span> <span class=identifier>s</span><span class=special>)</span>
<span class=special>{</span>
<span class=identifier>int_multiset</span><span class=special>::</span><span class=identifier>const_iterator</span> <span class=identifier>it</span><span class=special>=</span><span class=identifier>s</span><span class=special>.</span><span class=identifier>begin</span><span class=special>();</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>advance</span><span class=special>(</span><span class=identifier>it</span><span class=special>,</span><span class=identifier>s</span><span class=special>.</span><span class=identifier>size</span><span class=special>()*</span><span class=number>3</span><span class=special>/</span><span class=number>4</span><span class=special>);</span> <span class=comment>// linear on s.size();</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>copy</span><span class=special>(</span><span class=identifier>it</span><span class=special>,</span><span class=identifier>s</span><span class=special>.</span><span class=identifier>end</span><span class=special>(),</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>ostream_iterator</span><span class=special>&lt;</span><span class=keyword>int</span><span class=special>&gt;(</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>cout</span><span class=special>,</span><span class=string>&quot;\n&quot;</span><span class=special>));</span>
<span class=special>}</span>
</pre></blockquote>
<p>
The problem with this code is that getting to the beginning of the desired subsequence
involves a linear traversal of the container. Ranked indices provide the mechanisms to do this
much faster:
</p>
<blockquote><pre>
<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special>&lt;</span>
<span class=keyword>int</span><span class=special>,</span>
<span class=identifier>indexed_by</span><span class=special>&lt;</span>
<span class=identifier>ranked_non_unique</span><span class=special>&lt;</span><span class=identifier>identity</span><span class=special>&lt;</span><span class=keyword>int</span><span class=special>&gt;</span> <span class=special>&gt;</span>
<span class=special>&gt;</span>
<span class=special>&gt;</span> <span class=identifier>int_multiset</span><span class=special>;</span>
<span class=keyword>void</span> <span class=identifier>output_above_75th_percentile</span><span class=special>(</span><span class=keyword>const</span> <span class=identifier>int_multiset</span><span class=special>&amp;</span> <span class=identifier>s</span><span class=special>)</span>
<span class=special>{</span>
<span class=identifier>int_multiset</span><span class=special>::</span><span class=identifier>const_iterator</span> <span class=identifier>it</span><span class=special>=</span><span class=identifier>s</span><span class=special>.</span><span class=identifier>nth</span><span class=special>(</span><span class=identifier>s</span><span class=special>.</span><span class=identifier>size</span><span class=special>()*</span><span class=number>3</span><span class=special>/</span><span class=number>4</span><span class=special>);</span> <span class=comment>// logarithmic</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>copy</span><span class=special>(</span><span class=identifier>it</span><span class=special>,</span><span class=identifier>s</span><span class=special>.</span><span class=identifier>end</span><span class=special>(),</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>ostream_iterator</span><span class=special>&lt;</span><span class=keyword>int</span><span class=special>&gt;(</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>cout</span><span class=special>,</span><span class=string>&quot;\n&quot;</span><span class=special>));</span>
<span class=special>}</span>
</pre></blockquote>
<p>
<code>nth(n)</code> returns an iterator to the element whose <i>rank</i>, i.e. its distance
from the beginning of the index, is <code>n</code>, and does so efficiently in logarithmic time.
Conversely, <code>rank(it)</code> computes in logarithmic time the rank of the element
pointed to by <code>it</code>, or <code>size()</code> if <code>it==end()</code>.
</p>
<blockquote><pre>
<span class=identifier>int_multiset</span><span class=special>::</span><span class=identifier>iterator</span> <span class=identifier>it</span><span class=special>=</span><span class=identifier>s</span><span class=special>.</span><span class=identifier>insert</span><span class=special>(</span><span class=number>10</span><span class=special>).</span><span class=identifier>first</span><span class=special>;</span>
<span class=identifier>int_multiset</span><span class=special>::</span><span class=identifier>size_type</span> <span class=identifier>r</span><span class=special>=</span><span class=identifier>s</span><span class=special>.</span><span class=identifier>rank</span><span class=special>(</span><span class=identifier>it</span><span class=special>);</span> <span class=comment>// rank of 10;</span>
</pre></blockquote>
<p>
Ranked indices provide the same interface as ordered indices plus several rank-related operations.
The cost of this extra functionality is higher memory consumption due to some internal additional
data (one word per element) and somewhat longer execution times in insertion and erasure
&#8212;in particular, erasing an element takes time proportional to <code>log(n)</code>, where
<code>n</code> is the number of elements in the index, whereas for ordered indices this time is
constant.
The <a href="../reference/rnk_indices.html">reference</a> describes these indices in complete detail.
</p>
<h3><a name="rnk_spec">Specification</a></h3>
<p>
The specification of ranked indices is done exactly as with <a href="basics.html#ord_spec">ordered indices</a>,
except that <code>ranked_unique</code> and <code>ranked_non_unique</code> are used instead.
</p>
<blockquote><pre>
<span class=special>(</span><span class=identifier>ranked_unique</span> <span class=special>|</span> <span class=identifier>ranked_non_unique</span><span class=special>)
</span><span class=special>&lt;[</span><i>(tag)</i><span class=special>[,</span><i>(key extractor)</i><span class=special>[,</span><i>(comparison predicate)</i><span class=special>]]]&gt;</span>
<span class=special>(</span><span class=identifier>ranked_unique</span> <span class=special>|</span> <span class=identifier>ranked_non_unique</span><span class=special>)</span>
<span class=special>&lt;[</span><i>(key extractor)</i><span class=special>[,</span><i>(comparison predicate)</i><span class=special>]]&gt;</span>
</pre></blockquote>
<h3><a name="rnk_ops">Rank operations</a></h3>
<p>
Besides <code>nth</code> and <code>rank</code>, ranked indices provide member functions
<ul>
<li><code>find_rank</code>,</li>
<li><code>lower_bound_rank</code>,</li>
<li><code>upper_bound_rank</code>,</li>
<li><code>equal_range_rank</code> and </li>
<li><code>range_rank</code></li>
</ul>
that behave as their normal
<a href="basics.html#special_lookup">lookup</a> and <a href="basics.html#range">range retrieval</a>
counterparts (<code>find</code>, <code>lower_bound</code> etc.) but return ranks rather than iterators.
</p>
<blockquote><pre>
<span class=keyword>void</span> <span class=identifier>percentile</span><span class=special>(</span><span class=keyword>int</span> <span class=identifier>n</span><span class=special>,</span><span class=keyword>const</span> <span class=identifier>int_multiset</span><span class=special>&amp;</span> <span class=identifier>s</span><span class=special>)</span>
<span class=special>{</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>cout</span><span class=special>&lt;&lt;</span><span class=identifier>n</span><span class=special>&lt;&lt;</span><span class=string>&quot; lies in the &quot;</span><span class=special>&lt;&lt;</span>
<span class=identifier>s</span><span class=special>.</span><span class=identifier>upper_bound_rank</span><span class=special>(</span><span class=identifier>n</span><span class=special>)*</span><span class=number>100.0</span><span class=special>/</span><span class=identifier>s</span><span class=special>.</span><span class=identifier>size</span><span class=special>()&lt;&lt;</span><span class=string>&quot; percentile\n&quot;</span><span class=special>;</span>
<span class=special>}</span>
</pre></blockquote>
<p>
You might think that <code>upper_bound_rank(n)</code> is mere shorthand for
<code>rank(upper_bound(n))</code>: in reality, though, you should prefer using
<code>*_rank</code> operations directly as they run faster than the
alternative formulations.
</p>
<h2><a name="hashed_indices">Hashed indices</a></h2>
<p>
Hashed indices constitute a trade-off with respect to ordered indices: if correctly used,
they provide much faster lookup of elements, at the expense of losing sorting
information.
Let us revisit our <code>employee_set</code> example: suppose a field for storing
the Social Security number is added, with the requisite that lookup by this
number should be as fast as possible. Instead of the usual ordered index, a
hashed index can be resorted to:
</p>
<blockquote><pre>
<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>multi_index_container</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>multi_index</span><span class=special>/</span><span class=identifier>hashed_index</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>multi_index</span><span class=special>/</span><span class=identifier>ordered_index</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>multi_index</span><span class=special>/</span><span class=identifier>identity</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>multi_index</span><span class=special>/</span><span class=identifier>member</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
<span class=keyword>struct</span> <span class=identifier>employee</span>
<span class=special>{</span>
<span class=keyword>int</span> <span class=identifier>id</span><span class=special>;</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span> <span class=identifier>name</span><span class=special>;</span>
<span class=keyword>int</span> <span class=identifier>ssnumber</span><span class=special>;</span>
<span class=identifier>employee</span><span class=special>(</span><span class=keyword>int</span> <span class=identifier>id</span><span class=special>,</span><span class=keyword>const</span> <span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>&amp;</span> <span class=identifier>name</span><span class=special>,</span><span class=keyword>int</span> <span class=identifier>ssnumber</span><span class=special>):</span>
<span class=identifier>id</span><span class=special>(</span><span class=identifier>id</span><span class=special>),</span><span class=identifier>name</span><span class=special>(</span><span class=identifier>name</span><span class=special>),</span><span class=identifier>ssnumber</span><span class=special>(</span><span class=identifier>ssnumber</span><span class=special>){}</span>
<span class=keyword>bool</span> <span class=keyword>operator</span><span class=special>&lt;(</span><span class=keyword>const</span> <span class=identifier>employee</span><span class=special>&amp;</span> <span class=identifier>e</span><span class=special>)</span><span class=keyword>const</span><span class=special>{</span><span class=keyword>return</span> <span class=identifier>id</span><span class=special>&lt;</span><span class=identifier>e</span><span class=special>.</span><span class=identifier>id</span><span class=special>;}</span>
<span class=special>};</span>
<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special>&lt;</span>
<span class=identifier>employee</span><span class=special>,</span>
<span class=identifier>indexed_by</span><span class=special>&lt;</span>
<span class=comment>// sort by employee::operator&lt;</span>
<span class=identifier>ordered_unique</span><span class=special>&lt;</span><span class=identifier>identity</span><span class=special>&lt;</span><span class=identifier>employee</span><span class=special>&gt;</span> <span class=special>&gt;,</span>
<span class=comment>// sort by less&lt;string&gt; on name</span>
<span class=identifier>ordered_non_unique</span><span class=special>&lt;</span><span class=identifier>member</span><span class=special>&lt;</span><span class=identifier>employee</span><span class=special>,</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>,&amp;</span><span class=identifier>employee</span><span class=special>::</span><span class=identifier>name</span><span class=special>&gt;</span> <span class=special>&gt;,</span>
<span class=comment>// hashed on ssnumber</span>
<span class=identifier>hashed_unique</span><span class=special>&lt;</span><span class=identifier>member</span><span class=special>&lt;</span><span class=identifier>employee</span><span class=special>,</span><span class=keyword>int</span><span class=special>,&amp;</span><span class=identifier>employee</span><span class=special>::</span><span class=identifier>ssnumber</span><span class=special>&gt;</span> <span class=special>&gt;</span>
<span class=special>&gt;</span>
<span class=special>&gt;</span> <span class=identifier>employee_set</span>
</pre></blockquote>
<p>
Note that the hashed index does not guarantee any particular ordering of the
elements: so, for instance, we cannot efficiently query the employees whose SSN is
greater than a given number. Usually, you must consider these restrictions when
determining whether a hashed index is preferred over an ordered one.
</p>
<p>
Hashed indices replicate the interface as <code>std::unordered_set</code> and
<code>std::unordered_multiset</code>, with only minor differences where required
by the general constraints of <code>multi_index_container</code>s, and provide
additional useful capabilities like in-place updating of elements.
Check the <a href="../reference/hash_indices.html">reference</a> for a
complete specification of the interface of hashed indices,
and <a href="../examples.html#example8">example 8</a> and
<a href="../examples.html#example9">example 9</a> for practical applications.
</p>
</p>
<h3><a name="hash_unique_non_unique">Unique and non-unique variants</a></h3>
<p>
Just like ordered indices, hashed indices have unique and non-unique variants, selected
with the specifiers <code>hashed_unique</code> and <code>hashed_non_unique</code>,
respectively. In the latter case, elements with equivalent keys are kept together and can
be jointly retrieved by means of the <code>equal_range</code> member function.
</p>
<h3><a name="hash_spec">Specification</a></h3>
<p>
Hashed indices specifiers have two alternative syntaxes, depending on whether
<a href="basics.html#tagging">tags</a> are provided or not:
</p>
<blockquote><pre>
<span class=special>(</span><span class=identifier>hashed_unique</span> <span class=special>|</span> <span class=identifier>hashed_non_unique</span><span class=special>)
</span><span class=special>&lt;[</span><i>(tag)</i><span class=special>[,</span><i>(key extractor)</i><span class=special>[,</span><i>(hash function)</i><span class=special>[,</span><i>(equality predicate)</i><span class=special>]]]]&gt;</span>
<span class=special>(</span><span class=identifier>hashed_unique</span> <span class=special>|</span> <span class=identifier>hashed_non_unique</span><span class=special>)</span>
<span class=special>&lt;[</span><i>(key extractor)</i><span class=special>[,</span><i>(hash function)</i><span class=special>[,</span><i>(equality predicate)</i><span class=special>]]]&gt;</span>
</pre></blockquote>
<p>
The key extractor parameter works in exactly the same way as for
<a href="basics.html#key_extraction">ordered indices</a>; lookup, insertion,
etc., are based on the key returned by the extractor rather than the whole
element.
</p>
<p>
The hash function is the very core of the fast lookup capabilities of this type of
indices: a hasher is just a unary function object
returning an <code>std::size_t</code> value for any given
key. In general, it is impossible that every key map to a different hash value, for
the space of keys can be greater than the number of permissible hash codes: what
makes for a good hasher is that the probability of a collision (two different
keys with the same hash value) is as close to zero as possible. This is a statistical
property depending on the typical distribution of keys in a given application, so
it is not feasible to have a general-purpose hash function with excellent results
in <i>every</i> possible scenario; the default value for this parameter uses
<a href="../../../functional/hash/index.html">Boost.Hash</a>, which often provides good
enough results.
</p>
<p>
The equality predicate is used to determine whether two keys are to be treated
as the same. The default
value <code>std::equal_to&lt;KeyFromValue::result_type&gt;</code> is in most
cases exactly what is needed, so very rarely will you have to provide
your own predicate. Note that hashed indices require that two
equivalent keys have the same hash value, which
in practice greatly reduces the freedom in choosing an equality predicate.
</p>
<h3><a name="hash_lookup">Lookup</a></h3>
<p>
The lookup interface of hashed indices consists in member functions
<code>find</code>, <code>count</code> and <code>equal_range</code>.
Note that <code>lower_bound</code> and <code>upper_bound</code> are not
provided, as there is no intrinsic ordering of keys in this type of indices.
</p>
<p>
Just as with ordered indices, these member functions take keys
as their search arguments, rather than entire objects. Remember that
ordered indices lookup operations are further augmented to accept
<i>compatible keys</i>, which can roughly be regarded as "subkeys".
For hashed indices, a concept of
<a href="../reference/hash_indices.html#lookup">compatible key</a> is also
supported, though its usefulness is much more limited: basically,
a compatible key is an object which is entirely equivalent to
a native object of <code>key_type</code> value, though maybe with
a different internal representation:
</p>
<blockquote><pre>
<span class=comment>// US SSN numbering scheme</span>
<span class=keyword>struct</span> <span class=identifier>ssn</span>
<span class=special>{</span>
<span class=identifier>ssn</span><span class=special>(</span><span class=keyword>int</span> <span class=identifier>area_no</span><span class=special>,</span><span class=keyword>int</span> <span class=identifier>group_no</span><span class=special>,</span><span class=keyword>int</span> <span class=identifier>serial_no</span><span class=special>):</span>
<span class=identifier>area_no</span><span class=special>(</span><span class=identifier>area_no</span><span class=special>),</span><span class=identifier>group_no</span><span class=special>(</span><span class=identifier>group_no</span><span class=special>),</span><span class=identifier>serial_no</span><span class=special>(</span><span class=identifier>serial_no</span><span class=special>)</span>
<span class=special>{}</span>
<span class=keyword>int</span> <span class=identifier>to_int</span><span class=special>()</span><span class=keyword>const</span>
<span class=special>{</span>
<span class=keyword>return</span> <span class=identifier>serial_no</span><span class=special>+</span><span class=number>10000</span><span class=special>*</span><span class=identifier>group_no</span><span class=special>+</span><span class=number>1000000</span><span class=special>*</span><span class=identifier>area_no</span><span class=special>;</span>
<span class=special>}</span>
<span class=keyword>private</span><span class=special>:</span>
<span class=keyword>int</span> <span class=identifier>area_no</span><span class=special>;</span>
<span class=keyword>int</span> <span class=identifier>group_no</span><span class=special>;</span>
<span class=keyword>int</span> <span class=identifier>serial_no</span><span class=special>;</span>
<span class=special>};</span>
<span class=comment>// interoperability with SSNs in raw int form</span>
<span class=keyword>struct</span> <span class=identifier>ssn_equal</span>
<span class=special>{</span>
<span class=keyword>bool</span> <span class=keyword>operator</span><span class=special>()(</span><span class=keyword>const</span> <span class=identifier>ssn</span><span class=special>&amp;</span> <span class=identifier>x</span><span class=special>,</span><span class=keyword>int</span> <span class=identifier>y</span><span class=special>)</span><span class=keyword>const</span>
<span class=special>{</span>
<span class=keyword>return</span> <span class=identifier>x</span><span class=special>.</span><span class=identifier>to_int</span><span class=special>()==</span><span class=identifier>y</span><span class=special>;</span>
<span class=special>}</span>
<span class=keyword>bool</span> <span class=keyword>operator</span><span class=special>()(</span><span class=keyword>int</span> <span class=identifier>x</span><span class=special>,</span><span class=keyword>const</span> <span class=identifier>ssn</span><span class=special>&amp;</span> <span class=identifier>y</span><span class=special>)</span><span class=keyword>const</span>
<span class=special>{</span>
<span class=keyword>return</span> <span class=identifier>x</span><span class=special>==</span><span class=identifier>y</span><span class=special>.</span><span class=identifier>to_int</span><span class=special>();</span>
<span class=special>}</span>
<span class=special>};</span>
<span class=keyword>struct</span> <span class=identifier>ssn_hash</span>
<span class=special>{</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>size_t</span> <span class=keyword>operator</span><span class=special>()(</span><span class=keyword>const</span> <span class=identifier>ssn</span><span class=special>&amp;</span> <span class=identifier>x</span><span class=special>)</span><span class=keyword>const</span>
<span class=special>{</span>
<span class=keyword>return</span> <span class=identifier>boost</span><span class=special>::</span><span class=identifier>hash</span><span class=special>&lt;</span><span class=keyword>int</span><span class=special>&gt;()(</span><span class=identifier>x</span><span class=special>.</span><span class=identifier>to_int</span><span class=special>());</span>
<span class=special>}</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>size_t</span> <span class=keyword>operator</span><span class=special>()(</span><span class=keyword>int</span> <span class=identifier>x</span><span class=special>)</span><span class=keyword>const</span>
<span class=special>{</span>
<span class=keyword>return</span> <span class=identifier>boost</span><span class=special>::</span><span class=identifier>hash</span><span class=special>&lt;</span><span class=keyword>int</span><span class=special>&gt;()(</span><span class=identifier>x</span><span class=special>);</span>
<span class=special>}</span>
<span class=special>};</span>
<span class=keyword>typedef</span> <span class=identifier>employee_set</span><span class=special>::</span><span class=identifier>nth_index</span><span class=special>&lt;</span><span class=number>2</span><span class=special>&gt;::</span><span class=identifier>type</span> <span class=identifier>employee_set_by_ssn</span><span class=special>;</span>
<span class=identifier>employee_set</span> <span class=identifier>es</span><span class=special>;</span>
<span class=identifier>employee_set_by_ssn</span><span class=special>&amp;</span> <span class=identifier>ssn_index</span><span class=special>=</span><span class=identifier>es</span><span class=special>.</span><span class=identifier>get</span><span class=special>&lt;</span><span class=number>2</span><span class=special>&gt;();</span>
<span class=special>...</span>
<span class=comment>// find an employee by ssn</span>
<span class=identifier>employee</span> <span class=identifier>e</span><span class=special>=*(</span><span class=identifier>ssn_index</span><span class=special>.</span><span class=identifier>find</span><span class=special>(</span><span class=identifier>ssn</span><span class=special>(</span><span class=number>12</span><span class=special>,</span><span class=number>1005</span><span class=special>,</span><span class=number>20678</span><span class=special>),</span><span class=identifier>ssn_hash</span><span class=special>(),</span><span class=identifier>ssn_equal</span><span class=special>()));</span>
</pre></blockquote>
<p>
In the example, we provided a hash functor <code>ssn_hash</code> and an
equality predicate <code>ssn_equal</code> allowing for interoperability
between <code>ssn</code> objects and the raw <code>int</code>s stored as
<code>SSN</code>s in <code>employee_set</code>.
</p>
<p>
By far, the most useful application of compatible keys in the context
of hashed indices lies in the fact that they allow for seamless usage of
<a href="key_extraction.html#composite_keys">composite keys</a>.
</p>
<h3><a name="hash_updating">Updating</a></h3>
<p>
Hashed indices have
<a href="../reference/hash_indices.html#replace"><code>replace</code></a>,
<a href="../reference/hash_indices.html#modify"><code>modify</code></a> and
<a href="../reference/hash_indices.html#modify_key"><code>modify_key</code></a>
member functions, with the same functionality as in ordered indices.
</p>
<h3><a name="guarantees">Guarantees on iterator validity and exception safety</a></h3>
<p>
Due to the internal constraints imposed by the Boost.MultiIndex framework,
hashed indices provide guarantees on iterator validity and
exception safety that are actually stronger than required by the
C++ standard with respect to unordered associative containers:
<ul>
<li>Iterator validity is preserved in any case during insertion or rehashing:
C++ unordered associative containers can invalidate iterators when a rehash (implicit or explicit)
is performed.</li>
<li>Erasing an element or range of elements via iterators does not throw ever,
as the internal hash function and equality predicate objects are not actually
invoked.</li>
<li><code>rehash</code> provides the strong exception safety guarantee
unconditionally. The standard only warrants it for unordered associative containers if the internal hash function and
equality predicate objects do not throw. The somewhat surprising consequence
is that a standard-compliant <code>std::unordered_set</code> might erase
elements if an exception is thrown during rehashing!</li>
</ul>
In general, these stronger guarantees play in favor of the user's convenience,
specially that which refers to iterator stability. A (hopefully minimal)
degradation in performance might result in exchange for these commodities,
though.
</p>
<h2><a name="rnd_indices">Random access indices</a></h2>
<p>
Random access indices offer the same kind of functionality as
<a href="basics.html#seq_indices">sequenced indices</a>, with the extra advantages
that their iterators are random access, and <code>operator[]</code>
and <code>at()</code> are provided for accessing
elements based on their position in the index. Let us rewrite a
container used in a previous <a href="basics.html#list_fast_lookup">example</a>,
using random access instead of sequenced indices:
</p>
<blockquote><pre>
<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>multi_index_container</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>multi_index</span><span class=special>/</span><span class=identifier>random_access_index</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>multi_index</span><span class=special>/</span><span class=identifier>ordered_index</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>multi_index</span><span class=special>/</span><span class=identifier>identity</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
<span class=comment>// text container with fast lookup based on a random access index</span>
<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special>&lt;</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>,</span>
<span class=identifier>indexed_by</span><span class=special>&lt;</span>
<span class=identifier>random_access</span><span class=special>&lt;&gt;,</span>
<span class=identifier>ordered_non_unique</span><span class=special>&lt;</span><span class=identifier>identity</span><span class=special>&lt;</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>&gt;</span> <span class=special>&gt;</span>
<span class=special>&gt;</span>
<span class=special>&gt;</span> <span class=identifier>text_container</span><span class=special>;</span>
<span class=comment>// global text container object</span>
<span class=identifier>text_container</span> <span class=identifier>tc</span><span class=special>;</span>
</pre></blockquote>
<p>
Random access capabilities allow us to efficiently write code
like the following:
</p>
<blockquote><pre>
<span class=keyword>void</span> <span class=identifier>print_page</span><span class=special>(</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>size_t</span> <span class=identifier>page_num</span><span class=special>)</span>
<span class=special>{</span>
<span class=keyword>static</span> <span class=keyword>const</span> <span class=identifier>std</span><span class=special>::</span><span class=identifier>size_t</span> <span class=identifier>words_per_page</span><span class=special>=</span><span class=number>50</span><span class=special>;</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>size_t</span> <span class=identifier>pos0</span><span class=special>=</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>min</span><span class=special>(</span><span class=identifier>tc</span><span class=special>.</span><span class=identifier>size</span><span class=special>(),</span><span class=identifier>page_num</span><span class=special>*</span><span class=identifier>words_per_page</span><span class=special>);</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>size_t</span> <span class=identifier>pos1</span><span class=special>=</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>min</span><span class=special>(</span><span class=identifier>tc</span><span class=special>.</span><span class=identifier>size</span><span class=special>(),</span><span class=identifier>pos0</span><span class=special>+</span><span class=identifier>words_per_page</span><span class=special>);</span>
<span class=comment>// note random access iterators can be added offsets</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>copy</span><span class=special>(</span>
<span class=identifier>tc</span><span class=special>.</span><span class=identifier>begin</span><span class=special>()+</span><span class=identifier>pos0</span><span class=special>,</span><span class=identifier>tc</span><span class=special>.</span><span class=identifier>begin</span><span class=special>()+</span><span class=identifier>pos1</span><span class=special>,</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>ostream_iterator</span><span class=special>&lt;</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>&gt;(</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>cout</span><span class=special>));</span>
<span class=special>}</span>
<span class=keyword>void</span> <span class=identifier>print_random_word</span><span class=special>()</span>
<span class=special>{</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>cout</span><span class=special>&lt;&lt;</span><span class=identifier>tc</span><span class=special>[</span><span class=identifier>rand</span><span class=special>()%</span><span class=identifier>tc</span><span class=special>.</span><span class=identifier>size</span><span class=special>()];</span>
<span class=special>}</span>
</pre></blockquote>
<p>
This added flexibility comes at a price: insertions and deletions at positions
other than the end of the index have linear complexity, whereas these operations
are constant time for sequenced indices. This situation is reminiscent of the
differences in complexity behavior between <code>std::list</code> and
<code>std::vector</code>: in the case of random access indices, however,
insertions and deletions never incur any element copying, so the actual
performance of these operations can be acceptable, despite the theoretical
disadvantage with respect to sequenced indices.
</p>
<p>
<a href="../examples.html#example10">Example 10</a> and
<a href="../examples.html#example11">example 11</a> in the examples section put
random access indices in practice.
</p>
<h3><a name="rnd_spec">Specification</a></h3>
<p>
Random access indices are specified with the <code>random_access</code> construct,
where the <a href="basics.html#tagging">tag</a> parameter is, as usual, optional:
</p>
<blockquote><pre>
<span class=identifier>random_access</span><span class=special>&lt;[</span><i>(tag)</i><span class=special>]&gt;</span>
</pre></blockquote>
<h3><a name="rnd_interface">Interface</a></h3>
<p>
All public functions offered by sequenced indices are also provided
by random access indices, so that the latter can act as a drop-in replacement
of the former (save with respect to their complexity bounds, as explained above).
Besides, random access
indices have <code>operator[]</code> and <code>at()</code> for positional
access to the elements, and member functions
<a href="../reference/rnd_indices.html#capacity_memfun"><code>capacity</code></a> and
<a href="../reference/rnd_indices.html#reserve"><code>reserve</code></a>
that control internal reallocation in a similar manner as the homonym
facilities in <code>std::vector</code>. Check the
<a href="../reference/rnd_indices.html">reference</a> for details.
</p>
<h3><a name="rnd_vs_vector">Comparison with <code>std::vector</code></a></h3>
<p>
It is tempting to see random access indices as an analogue of <code>std::vector</code>
for use in Boost.MultiIndex, but this metaphor can be misleading, as both constructs,
though similar in many respects, show important semantic differences. An
advantage of random access indices is that their iterators, as well as references
to their elements, are <i>stable</i>, that is, they remain valid after any insertions
or deletions. On the other hand, random access indices have several disadvantages with
respect to <code>std::vector</code>s:
<ul>
<li>They do not provide <i>memory contiguity</i>, a property
of <code>std::vector</code>s by which elements are stored adjacent to one
another in a single block of memory.
</li>
<li>As usual in Boost.MultiIndex, elements of random access indices are immutable
and can only be modified through member functions
<a href="../reference/rnd_indices.html#replace"><code>replace</code></a> and
<a href="../reference/rnd_indices.html#modify"><code>modify</code></a>.
This precludes the usage of many mutating
algorithms that are nonetheless applicable to <code>std::vector</code>s.
</li>
</ul>
The latter shortcoming can be partially remedied by means of the
<a href="#rearrange">rearranging interface</a> these indices provide.
</p>
<p>
In general, it is more instructive to regard random access indices as
a variation of sequenced indices providing random access semantics, instead
of insisting on the <code>std::vector</code> analogy.
</p>
<h2><a name="rearrange">Index rearranging</a></h2>
<p>
By design, index elements are immutable, i.e. iterators only grant
<code>const</code> access to them, and only through the provided
updating interface (<code>replace</code>, <code>modify</code> and
<code>modify_key</code>) can the elements be modified. This restriction
is set up so that the internal invariants of key-based indices are
not broken (for instance, ascending order traversal in ordered
indices), but induces important limitations in non key-based indices:
</p>
<blockquote><pre>
<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special>&lt;</span>
<span class=keyword>int</span><span class=special>,</span>
<span class=identifier>indexed_by</span><span class=special>&lt;</span>
<span class=identifier>random_access</span><span class=special>&lt;&gt;,</span>
<span class=identifier>ordered_unique</span><span class=special>&lt;</span><span class=identifier>identity</span><span class=special>&lt;</span><span class=keyword>int</span><span class=special>&gt;</span> <span class=special>&gt;</span>
<span class=special>&gt;</span>
<span class=special>&gt;</span> <span class=identifier>container</span><span class=special>;</span>
<span class=identifier>container</span> <span class=identifier>c</span><span class=special>;</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>mt19937</span> <span class=identifier>rng</span><span class=special>;</span>
<span class=special>...</span>
<span class=comment>// compiler error: assignment to read-only objects</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>shuffle</span><span class=special>(</span><span class=identifier>c</span><span class=special>.</span><span class=identifier>begin</span><span class=special>(),</span><span class=identifier>c</span><span class=special>.</span><span class=identifier>end</span><span class=special>(),</span><span class=identifier>rng</span><span class=special>);</span>
</pre></blockquote>
<p>
What is unfortunate about the previous example is that the operation
performed by <code>std::shuffle</code> is potentially compatible
with <code>multi_index_container</code> invariants, as its result can be
described by a permutation of the elements in the random access index
with no actual modifications to the elements themselves. There are many
more examples of such compatible algorithms in the C++ standard library,
like for instance all sorting and partition functions.
</p>
<p>
Sequenced and random access indices provide a means to take advantage
of such external algorithms. In order to introduce this facility we need
a preliminary concept: a <i>view</i> of an index is defined as
some iterator range [<code>first</code>,<code>last</code>) over the
elements of the index such that all its elements are contained in the
range exactly once. Continuing with our example, we can apply
<code>std::shuffle</code> on an ad hoc view obtained from the
container:
</p>
<blockquote><pre>
<span class=comment>// note that the elements of the view are not copies of the elements
// in c, but references to them</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>vector</span><span class=special>&lt;</span><span class=identifier>boost</span><span class=special>::</span><span class=identifier>reference_wrapper</span><span class=special>&lt;</span><span class=keyword>const</span> <span class=keyword>int</span><span class=special>&gt;</span> <span class=special>&gt;</span> <span class=identifier>v</span><span class=special>;</span>
<span class=identifier>BOOST_FOREACH</span><span class=special>(</span><span class=keyword>const</span> <span class=keyword>int</span><span class=special>&amp;</span> <span class=identifier>i</span><span class=special>,</span><span class=identifier>c</span><span class=special>)</span><span class=identifier>v</span><span class=special>.</span><span class=identifier>push_back</span><span class=special>(</span><span class=identifier>boost</span><span class=special>::</span><span class=identifier>cref</span><span class=special>(</span><span class=identifier>i</span><span class=special>));</span>
<span class=comment>// this compiles OK, as reference_wrappers are swappable</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>shuffle</span><span class=special>(</span><span class=identifier>v</span><span class=special>.</span><span class=identifier>begin</span><span class=special>(),</span><span class=identifier>v</span><span class=special>.</span><span class=identifier>end</span><span class=special>(),</span><span class=identifier>rng</span><span class=special>);</span>
</pre></blockquote>
<p>
Elements of <code>v</code> are <code>reference_wrapper</code>s (from
<a href="../../../../doc/html/ref.html">Boost.Ref</a>) to the actual elements
in the multi-index container. These objects still do not allow modification
of the referenced entities, but they are swappable,
which is the only requirement <code>std::shuffle</code> imposes. Once
we have our desired rearrange stored in the view, we can transfer it to
the container with
</p>
<blockquote><pre>
<span class=identifier>c</span><span class=special>.</span><span class=identifier>rearrange</span><span class=special>(</span><span class=identifier>v</span><span class=special>.</span><span class=identifier>begin</span><span class=special>());</span>
</pre></blockquote>
<p>
<code>rearrange</code> accepts an input iterator signaling the beginning
of the external view (and end iterator is not needed since the length of
the view is the same as that of the index) and internally relocates the
elements of the index so that their traversal order matches the view.
Albeit with some circumventions, <code>rearrange</code> allows for the
application of a varied range of algorithms to non key-based indices.
Please note that the view concept is very general, and in no way tied
to the particular implementation example shown above. For instance, indices
of a <code>multi_index_container</code> are indeed views with respect to
its non key-based indices:
</p>
<blockquote><pre>
<span class=comment>// rearrange as index #1 (ascending order)</span>
<span class=identifier>c</span><span class=special>.</span><span class=identifier>rearrange</span><span class=special>(</span><span class=identifier>c</span><span class=special>.</span><span class=identifier>get</span><span class=special>&lt;</span><span class=number>1</span><span class=special>&gt;().</span><span class=identifier>begin</span><span class=special>());</span>
<span class=comment>// rearrange in descending order</span>
<span class=identifier>c</span><span class=special>.</span><span class=identifier>rearrange</span><span class=special>(</span><span class=identifier>c</span><span class=special>.</span><span class=identifier>get</span><span class=special>&lt;</span><span class=number>1</span><span class=special>&gt;().</span><span class=identifier>rbegin</span><span class=special>());</span>
</pre></blockquote>
<p>
The only important requirement imposed on views is that they must be
<i>free</i>, i.e. they are not affected by relocations on the base index:
thus, <code>rearrange</code> does not accept the following:
</p>
<blockquote><pre>
<span class=comment>// undefined behavior: [rbegin(),rend()) is not free with respect
// to the base index</span>
<span class=identifier>c</span><span class=special>.</span><span class=identifier>rearrange</span><span class=special>(</span><span class=identifier>c</span><span class=special>.</span><span class=identifier>rbegin</span><span class=special>());</span>
</pre></blockquote>
<p>
The view concept is defined in detail in the
<a href="../reference/indices.html#views">reference</a>.
See <a href="../examples.html#example11">example 11</a> in the examples section
for a demonstration of use of <code>rearrange</code>.
</p>
<h2><a name="iterator_to"><code>iterator_to</code></a></h2>
<p>
All indices of Boost.MultiIndex provide a member function called <code>iterator_to</code>
which returns an iterator to a given element of the container:
</p>
<blockquote><pre>
<span class=identifier>multi_index_container</span><span class=special>&lt;</span>
<span class=keyword>int</span><span class=special>,</span>
<span class=identifier>indexed_by</span><span class=special>&lt;</span><span class=identifier>sequenced</span><span class=special>&lt;&gt;</span> <span class=special>&gt;</span>
<span class=special>&gt;</span> <span class=identifier>c</span><span class=special>;</span>
<span class=special>...</span>
<span class=comment>// convoluted way to do c.pop_back()</span>
<span class=identifier>c</span><span class=special>.</span><span class=identifier>erase</span><span class=special>(</span><span class=identifier>c</span><span class=special>.</span><span class=identifier>iterator_to</span><span class=special>(</span><span class=identifier>c</span><span class=special>.</span><span class=identifier>back</span><span class=special>()));</span>
<span class=comment>// The following, though similar to the previous code,
// does not work: iterator_to accepts a reference to
// the element in the container, not a copy.</span>
<span class=keyword>int</span> <span class=identifier>x</span><span class=special>=</span><span class=identifier>c</span><span class=special>.</span><span class=identifier>back</span><span class=special>();</span>
<span class=identifier>c</span><span class=special>.</span><span class=identifier>erase</span><span class=special>(</span><span class=identifier>c</span><span class=special>.</span><span class=identifier>iterator_to</span><span class=special>(</span><span class=identifier>x</span><span class=special>));</span> <span class=comment>// run-time failure ensues</span>
</pre></blockquote>
<p>
<code>iterator_to</code> provides a way to retrieve an iterator to an element
from a pointer to the element, thus making iterators and pointers interchangeable
for the purposes of element pointing (not so for traversal) in many situations.
This notwithstanding, it is not the aim of <code>iterator_to</code> to
promote the usage of pointers as substitutes for real iterators: the latter are
specifically designed for handling the elements of a container,
and not only benefit from the iterator orientation of container interfaces,
but are also capable of exposing many more programming bugs than raw pointers, both
at compile and run time. <code>iterator_to</code> is thus meant to be used
in scenarios where access via iterators is not suitable or desireable:
<ul>
<li>Interoperability with preexisting APIs based on pointers or references.</li>
<li>Publication of pointer-based interfaces (for instance, when
designing a C-compatible library).
</li>
<li>The exposure of pointers in place of iterators can act as a <i>type
erasure</i> barrier effectively decoupling the user of the code
from the implementation detail of which particular container is being
used. Similar techniques, like the famous Pimpl idiom, are used
in large projects to reduce dependencies and build times.
</li>
<li>Self-referencing contexts where an element acts upon its owner
container and no iterator to itself is available.
</li>
</ul>
</p>
<h2><a name="ordered_node_compression">Ordered indices node compression</a></h2>
<p>
Ordered and ranked indices are implemented by means of a data structure
known as a <i>red-black tree</i>. Nodes of a red-back tree contain pointers
to the parent and the two children nodes, plus a 1-bit field referred to as
the <i>node color</i> (hence the name of the structure). Due to alignment
issues, on most architectures the color field occupies one entire word, that is,
4 bytes in 32-bit systems and 8 bytes in 64-bit environments. This waste
of space can be avoided by embedding the color bit inside one of the
node pointers, provided not all the bits of the pointer representation contain
useful information: this is precisely the case in many architectures where
such nodes are aligned to even addresses, which implies that the least
significant bit of the address must always be zero.
</p>
<p>
Boost.MultiIndex ordered and ranked indices implement this type of node compression
whenever applicable. As compared with common implementations of the STL
container <code>std::set</code>, node compression can
result in a reduction of header overload by 25% (from 16 to 12 bytes on
typical 32-bit architectures, and from 32 to 24 bytes on 64-bit systems).
The impact on performance of this optimization has been checked to be negligible
for moderately sized containers, whereas containers with many elements (hundreds
of thousands or more) perform faster with this optimization, most likely due to
L1 and L2 cache effects.
</p>
<p>
Node compression can be disabled by globally setting the macro
<code>BOOST_MULTI_INDEX_DISABLE_COMPRESSED_ORDERED_INDEX_NODES</code>.
</p>
<hr>
<div class="prev_link"><a href="basics.html"><img src="../prev.gif" alt="basics" border="0"><br>
Basics
</a></div>
<div class="up_link"><a href="index.html"><img src="../up.gif" alt="Boost.MultiIndex tutorial" border="0"><br>
Boost.MultiIndex tutorial
</a></div>
<div class="next_link"><a href="key_extraction.html"><img src="../next.gif" alt="key estraction" border="0"><br>
Key extraction
</a></div><br clear="all" style="clear: all;">
<br>
<p>Revised August 29th 2017</p>
<p>&copy; Copyright 2003-2017 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz.
Distributed under the Boost Software
License, Version 1.0. (See accompanying file <a href="../../../../LICENSE_1_0.txt">
LICENSE_1_0.txt</a> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">
http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</body>
</html>

View File

@@ -0,0 +1,968 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0.1 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Boost.MultiIndex Documentation - Tutorial - Key extraction</title>
<link rel="stylesheet" href="../style.css" type="text/css">
<link rel="start" href="../index.html">
<link rel="prev" href="indices.html">
<link rel="up" href="index.html">
<link rel="next" href="creation.html">
</head>
<body>
<h1><img src="../../../../boost.png" alt="boost.png (6897 bytes)" align=
"middle" width="277" height="86">Boost.MultiIndex Tutorial: Key extraction</h1>
<div class="prev_link"><a href="indices.html"><img src="../prev.gif" alt="index types" border="0"><br>
Index types
</a></div>
<div class="up_link"><a href="index.html"><img src="../up.gif" alt="Boost.MultiIndex tutorial" border="0"><br>
Boost.MultiIndex tutorial
</a></div>
<div class="next_link"><a href="creation.html"><img src="../next.gif" alt="container creation" border="0"><br>
Container creation
</a></div><br clear="all" style="clear: all;">
<hr>
<h2>Contents</h2>
<ul>
<li><a href="#intro">Introduction</a>
<ul>
<li><a href="#read_write_key_extractors">Read/write key extractors</a></li>
</ul>
</li>
<li><a href="#predefined_key_extractors">Predefined key extractors</a>
<ul>
<li><a href="#identity"><code>identity</code></a></li>
<li><a href="#member"><code>member</code></a></li>
<li><a href="#const_mem_fun"><code>const_mem_fun</code>
and <code>mem_fun</code></a></li>
<li><a href="#global_fun"><code>global_fun</code></a></li>
</ul>
</li>
<li><a href="#user_defined_key_extractors">User-defined key extractors</a></li>
<li><a href="#composite_keys">Composite keys</a>
<ul>
<li><a href="#composite_keys_hash">Composite keys and hashed indices</a></li>
</ul>
</li>
<li><a href="#advanced_key_extractors">Advanced features of Boost.MultiIndex key
extractors</a></li>
</ul>
<h2><a name="intro">Introduction</a></h2>
<p>
STL associative containers have a notion of key, albeit in a somewhat incipient
form. So, the keys of such containers are identified by a nested type
<code>key_type</code>; for <code>std::set</code>s and <code>std::multiset</code>s,
<code>key_type</code> coincides with <code>value_type</code>, i.e. the key is the
element itself. <code>std::map</code> and <code>std::multimap</code> manage
elements of type <code>std::pair&lt;const Key,T&gt;</code>, where the first
member is the key. In either case, the process of obtaining the key from a
given element is implicitly fixed and cannot be customized by the user.
</p>
<p>
Fixed key extraction mechanisms like those performed by STL associative
containers do not scale well in the context of Boost.MultiIndex, where
several indices share their <code>value_type</code> definition but
might feature completely different lookup semantics. For this reason,
Boost.MultiIndex formalizes the concept of a
<a href="../reference/key_extraction.html#key_extractors"><code>Key
Extractor</code></a> in order to make it explicit and controllable
in the definition of key-based indices.
</p>
<p>
Intuitively speaking, a key extractor is a function object that accepts
a reference to an element and returns its associated key. The formal
concept also imposes some reasonable constraints about the stability
of the process, in the sense that extractors are assumed to
return the same key when passed the same element: this is in consonance
with the informal understanding that keys are actually some "part"
of the element and do not depend on external data.
</p>
<h3><a name="read_write_key_extractors">Read/write key extractors</a></h3>
<p>
A key extractor is called <i>read/write</i> if it returns a non-constant reference
to the key when passed a non-constant element, and it is called <i>read-only</i>
otherwise. Boost.MultiIndex requires that the key extractor be read/write
when using the <code>modify_key</code> member function of ordered and hashed
indices. In all other situations, read-only extractors suffice.
The section on <a href="#advanced_key_extractors">advanced features
of Boost.MultiIndex key extractors</a> details which of the predefined
key extractors are read/write.
</p>
<h2><a name="predefined_key_extractors">Predefined key extractors</a></h2>
<h3><a name="identity"><code>identity</code></a></h3>
<p>
The <a href="../reference/key_extraction.html#identity"><code>identity</code></a>
key extractor returns the entire base object as the associated key:
</p>
<blockquote><pre>
<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>multi_index_container</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>multi_index</span><span class=special>/</span><span class=identifier>ordered_index</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>multi_index</span><span class=special>/</span><span class=identifier>identity</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
<span class=identifier>multi_index_container</span><span class=special>&lt;</span>
<span class=keyword>int</span><span class=special>,</span>
<span class=identifier>indexed_by</span><span class=special>&lt;</span>
<span class=identifier>ordered_unique</span><span class=special>&lt;</span>
<span class=identifier>identity</span><span class=special>&lt;</span><span class=keyword>int</span><span class=special>&gt;</span> <span class=comment>// the key is the entire element</span>
<span class=special>&gt;</span>
<span class=special>&gt;</span>
<span class=special>&gt;</span> <span class=identifier>cont</span><span class=special>;</span>
</pre></blockquote>
<h3><a name="member"><code>member</code></a></h3>
<p>
<a href="../reference/key_extraction.html#member"><code>member</code></a>
key extractors return a reference to a specified
data field of the base object. For instance, in the following version of our
familiar employee container:
</p>
<blockquote><pre>
<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>multi_index_container</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>multi_index</span><span class=special>/</span><span class=identifier>ordered_index</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>multi_index</span><span class=special>/</span><span class=identifier>identity</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>multi_index</span><span class=special>/</span><span class=identifier>member</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special>&lt;</span>
<span class=identifier>employee</span><span class=special>,</span>
<span class=identifier>indexed_by</span><span class=special>&lt;</span>
<span class=identifier>ordered_unique</span><span class=special>&lt;</span><span class=identifier>identity</span><span class=special>&lt;</span><span class=identifier>employee</span><span class=special>&gt;</span> <span class=special>&gt;,</span>
<span class=identifier>ordered_non_unique</span><span class=special>&lt;</span><span class=identifier>member</span><span class=special>&lt;</span><span class=identifier>employee</span><span class=special>,</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>,&amp;</span><span class=identifier>employee</span><span class=special>::</span><span class=identifier>name</span><span class=special>&gt;</span> <span class=special>&gt;,</span>
<span class=identifier>ordered_unique</span><span class=special>&lt;</span><span class=identifier>member</span><span class=special>&lt;</span><span class=identifier>employee</span><span class=special>,</span><span class=keyword>int</span><span class=special>,&amp;</span><span class=identifier>employee</span><span class=special>::</span><span class=identifier>ssnumber</span><span class=special>&gt;</span> <span class=special>&gt;</span>
<span class=special>&gt;</span>
<span class=special>&gt;</span> <span class=identifier>employee_set</span><span class=special>;</span>
</pre></blockquote>
<p>
the second and third indices use <code>member</code> extractors on
<code>employee::name</code> and <code>employee::ssnumber</code>, respectively.
The specification of an instantiation of <code>member</code> is simple
yet a little contrived:
</p>
<blockquote><pre>
<span class=identifier>member</span><span class=special>&lt;</span><span class=identifier><i>(base type)</i></span><span class=special>,</span><span class=identifier><i>(key type)</i></span><span class=special>,</span><span class=identifier><i>(pointer to member)</i></span><span class=special>&gt;</span>
</pre></blockquote>
<p>
It might seem that the first and second parameters are superfluous,
since the type of the base object and of the associated data field are
already implicit in the pointer to member argument: unfortunately, it is
not possible to extract this information with current C++ mechanisms,
which makes the syntax of <code>member</code> a little too verbose.
</p>
<h3><a name="const_mem_fun"><code>const_mem_fun</code> and <code>mem_fun</code></a></h3>
<p>
Sometimes, the key of an index is not a concrete data member of the element,
but rather it is a value returned by a particular member function.
This resembles the notion of <i>calculated indices</i> supported by some
relational databases. Boost.MultiIndex supports this
kind of key extraction through
<a href="../reference/key_extraction.html#const_mem_fun"><code>const_mem_fun</code></a>.
Consider the following container where sorting on the third index
is based upon the length of the name field:
</p>
<blockquote><pre>
<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>multi_index_container</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>multi_index</span><span class=special>/</span><span class=identifier>ordered_index</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>multi_index</span><span class=special>/</span><span class=identifier>identity</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>multi_index</span><span class=special>/</span><span class=identifier>member</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>multi_index</span><span class=special>/</span><span class=identifier>mem_fun</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
<span class=keyword>struct</span> <span class=identifier>employee</span>
<span class=special>{</span>
<span class=keyword>int</span> <span class=identifier>id</span><span class=special>;</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span> <span class=identifier>name</span><span class=special>;</span>
<span class=identifier>employee</span><span class=special>(</span><span class=keyword>int</span> <span class=identifier>id</span><span class=special>,</span><span class=keyword>const</span> <span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>&amp;</span> <span class=identifier>name</span><span class=special>):</span><span class=identifier>id</span><span class=special>(</span><span class=identifier>id</span><span class=special>),</span><span class=identifier>name</span><span class=special>(</span><span class=identifier>name</span><span class=special>){}</span>
<span class=keyword>bool</span> <span class=keyword>operator</span><span class=special>&lt;(</span><span class=keyword>const</span> <span class=identifier>employee</span><span class=special>&amp;</span> <span class=identifier>e</span><span class=special>)</span><span class=keyword>const</span><span class=special>{</span><span class=keyword>return</span> <span class=identifier>id</span><span class=special>&lt;</span><span class=identifier>e</span><span class=special>.</span><span class=identifier>id</span><span class=special>;}</span>
<span class=comment>// returns the length of the name field</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>size_t</span> <span class=identifier>name_length</span><span class=special>()</span><span class=keyword>const</span><span class=special>{</span><span class=keyword>return</span> <span class=identifier>name</span><span class=special>.</span><span class=identifier>size</span><span class=special>();}</span>
<span class=special>};</span>
<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special>&lt;</span>
<span class=identifier>employee</span><span class=special>,</span>
<span class=identifier>indexed_by</span><span class=special>&lt;</span>
<span class=comment>// sort by employee::operator&lt;</span>
<span class=identifier>ordered_unique</span><span class=special>&lt;</span><span class=identifier>identity</span><span class=special>&lt;</span><span class=identifier>employee</span><span class=special>&gt;</span> <span class=special>&gt;,</span>
<span class=comment>// sort by less&lt;string&gt; on name</span>
<span class=identifier>ordered_non_unique</span><span class=special>&lt;</span><span class=identifier>member</span><span class=special>&lt;</span><span class=identifier>employee</span><span class=special>,</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>,&amp;</span><span class=identifier>employee</span><span class=special>::</span><span class=identifier>name</span><span class=special>&gt;</span> <span class=special>&gt;,</span>
<span class=comment>// sort by less&lt;int&gt; on name_length()</span>
<span class=identifier>ordered_non_unique</span><span class=special>&lt;</span>
<span class=identifier>const_mem_fun</span><span class=special>&lt;</span><span class=identifier>employee</span><span class=special>,</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>size_t</span><span class=special>,&amp;</span><span class=identifier>employee</span><span class=special>::</span><span class=identifier>name_length</span><span class=special>&gt;</span>
<span class=special>&gt;</span>
<span class=special>&gt;</span>
<span class=special>&gt;</span> <span class=identifier>employee_set</span><span class=special>;</span>
</pre></blockquote>
<p>
<code>const_mem_fun</code> usage syntax is similar to that of
<a href="#member"><code>member</code></a>:
</p>
<blockquote><pre>
<span class=identifier>const_mem_fun</span><span class=special>&lt;</span><span class=identifier><i>(base type)</i></span><span class=special>,</span><span class=identifier><i>(key type)</i></span><span class=special>,</span><span class=identifier><i>(pointer to member function)</i></span><span class=special>&gt;</span>
</pre></blockquote>
<p>
The member function referred to must be <code>const</code>, take no arguments and return
a value of the specified key type.
Almost always you will want to use a <code>const</code> member function,
since elements in a <code>multi_index_container</code> are treated as constant, much
as elements of an <code>std::set</code>. However, a
<a href="../reference/key_extraction.html#mem_fun"><code>mem_fun</code></a>
counterpart is provided for use with non-constant member functions, whose
applicability is discussed on the paragraph on
<a href="#advanced_key_extractors">advanced features
of Boost.MultiIndex key extractors</a>.
</p>
<p><a href="../examples.html#example2">Example 2</a> in the examples section
provides a complete program showing how to use <code>const_mem_fun</code>.
<p>
<h3><a name="global_fun"><code>global_fun</code></a></h3>
<p>
Whereas <code>const_mem_fun</code> and <code>mem_fun</code> are based on a
given member function of the base type from where the key is extracted,
<a href="../reference/key_extraction.html#global_fun"><code>global_fun</code></a>
takes a global function (or static member function) accepting the base
type as its parameter and returning the key:
</p>
<blockquote><pre>
<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>multi_index_container</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>multi_index</span><span class=special>/</span><span class=identifier>ordered_index</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>multi_index</span><span class=special>/</span><span class=identifier>global_fun</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
<span class=keyword>struct</span> <span class=identifier>rectangle</span>
<span class=special>{</span>
<span class=keyword>int</span> <span class=identifier>x0</span><span class=special>,</span><span class=identifier>y0</span><span class=special>;</span>
<span class=keyword>int</span> <span class=identifier>x1</span><span class=special>,</span><span class=identifier>y1</span><span class=special>;</span>
<span class=special>};</span>
<span class=keyword>unsigned</span> <span class=keyword>long</span> <span class=identifier>area</span><span class=special>(</span><span class=keyword>const</span> <span class=identifier>rectangle</span><span class=special>&amp;</span> <span class=identifier>r</span><span class=special>)</span>
<span class=special>{</span>
<span class=keyword>return</span> <span class=special>(</span><span class=keyword>unsigned</span> <span class=keyword>long</span><span class=special>)(</span><span class=identifier>r</span><span class=special>.</span><span class=identifier>x1</span><span class=special>-</span><span class=identifier>r</span><span class=special>.</span><span class=identifier>x0</span><span class=special>)*(</span><span class=identifier>r</span><span class=special>.</span><span class=identifier>x1</span><span class=special>-</span><span class=identifier>r</span><span class=special>.</span><span class=identifier>x0</span><span class=special>)+</span>
<span class=special>(</span><span class=keyword>unsigned</span> <span class=keyword>long</span><span class=special>)(</span><span class=identifier>r</span><span class=special>.</span><span class=identifier>y1</span><span class=special>-</span><span class=identifier>r</span><span class=special>.</span><span class=identifier>y0</span><span class=special>)*(</span><span class=identifier>r</span><span class=special>.</span><span class=identifier>y1</span><span class=special>-</span><span class=identifier>r</span><span class=special>.</span><span class=identifier>y0</span><span class=special>);</span>
<span class=special>}</span>
<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special>&lt;</span>
<span class=identifier>rectangle</span><span class=special>,</span>
<span class=identifier>indexed_by</span><span class=special>&lt;</span>
<span class=comment>// sort by increasing area</span>
<span class=identifier>ordered_non_unique</span><span class=special>&lt;</span><span class=identifier>global_fun</span><span class=special>&lt;</span><span class=keyword>const</span> <span class=identifier>rectangle</span><span class=special>&amp;,</span><span class=keyword>unsigned</span> <span class=keyword>long</span><span class=special>,&amp;</span><span class=identifier>area</span><span class=special>&gt;</span> <span class=special>&gt;</span>
<span class=special>&gt;</span>
<span class=special>&gt;</span> <span class=identifier>rectangle_container</span><span class=special>;</span>
</pre></blockquote>
<p>
The specification of <code>global_fun</code> obeys the following syntax:
</p>
<blockquote><pre>
<span class=identifier>global_fun</span><span class=special>&lt;</span><span class=identifier><i>(argument type)</i></span><span class=special>,</span><span class=identifier><i>(key type)</i></span><span class=special>,</span><span class=identifier><i>(pointer to function)</i></span><span class=special>&gt;</span>
</pre></blockquote>
<p>
where the argument type and key type must match <i>exactly</i> those in the
signature of the function used; for instance, in the example above the argument
type is <code>const rectangle&amp;</code>, without omitting the "<code>const</code>"
and "<code>&amp;</code>" parts. So, although most of the time the base type will be
accepted by constant reference, <code>global_fun</code> is also prepared to take
functions accepting their argument by value or by non-constant reference: this
latter case cannot generally be used directly in the specification of
<code>multi_index_container</code>s as their elements are treated as constant,
but the section on <a href="#advanced_key_extractors">advanced features
of Boost.MultiIndex key extractors</a> describes valid use cases of
key extraction based on such functions with a non-constant reference argument.
</p>
<p><a href="../examples.html#example2">Example 2</a> in the examples section
uses <code>gobal_fun</code>.
<p>
<h2><a name="user_defined_key_extractors">User-defined key extractors</a></h2>
<p>
Although the <a href="#predefined_key_extractors">predefined key extractors</a>
provided by Boost.MultiIndex are intended to serve most cases,
the user can also provide her own key extractors in more exotic situations,
as long as these conform to the
<a href="../reference/key_extraction.html#key_extractors"><code>Key
Extractor</code></a> concept.
</p>
<blockquote><pre>
<span class=comment>// some record class</span>
<span class=keyword>struct</span> <span class=identifier>record</span>
<span class=special>{</span>
<span class=identifier>boost</span><span class=special>::</span><span class=identifier>gregorian</span><span class=special>::</span><span class=identifier>date</span> <span class=identifier>d</span><span class=special>;</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span> <span class=identifier>str</span><span class=special>;</span>
<span class=special>};</span>
<span class=comment>// extracts a record's year</span>
<span class=keyword>struct</span> <span class=identifier>record_year</span>
<span class=special>{</span>
<span class=comment>// result_type typedef required by Key Extractor concept</span>
<span class=keyword>typedef</span> <span class=identifier>boost</span><span class=special>::</span><span class=identifier>gregorian</span><span class=special>::</span><span class=identifier>greg_year</span> <span class=identifier>result_type</span><span class=special>;</span>
<span class=identifier>result_type</span> <span class=keyword>operator</span><span class=special>()(</span><span class=keyword>const</span> <span class=identifier>record</span><span class=special>&amp;</span> <span class=identifier>r</span><span class=special>)</span><span class=keyword>const</span> <span class=comment>// operator() must be const</span>
<span class=special>{</span>
<span class=keyword>return</span> <span class=identifier>r</span><span class=special>.</span><span class=identifier>d</span><span class=special>.</span><span class=identifier>year</span><span class=special>();</span>
<span class=special>}</span>
<span class=special>};</span>
<span class=comment>// example of use of the previous key extractor</span>
<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special>&lt;</span>
<span class=identifier>record</span><span class=special>,</span>
<span class=identifier>indexed_by</span><span class=special>&lt;</span>
<span class=identifier>ordered_non_unique</span><span class=special>&lt;</span><span class=identifier>record_year</span><span class=special>&gt;</span> <span class=comment>// sorted by record's year</span>
<span class=special>&gt;</span>
<span class=special>&gt;</span> <span class=identifier>record_log</span><span class=special>;</span>
</pre></blockquote>
<p>
<a href="../examples.html#example6">Example 6</a> in the examples section
applies some user-defined key extractors in a complex scenario where
keys are accessed via pointers.
</p>
<h2><a name="composite_keys">Composite keys</a></h2>
<p>
In relational databases, composite keys depend on two or more fields of a given table.
The analogous concept in Boost.MultiIndex is modeled by means of
<a href="../reference/key_extraction.html#composite_key">
<code>composite_key</code></a>, as shown in the example:
</p>
<blockquote><pre>
<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>multi_index_container</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>multi_index</span><span class=special>/</span><span class=identifier>ordered_index</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>multi_index</span><span class=special>/</span><span class=identifier>member</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>multi_index</span><span class=special>/</span><span class=identifier>composite_key</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
<span class=keyword>struct</span> <span class=identifier>phonebook_entry</span>
<span class=special>{</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span> <span class=identifier>family_name</span><span class=special>;</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span> <span class=identifier>given_name</span><span class=special>;</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span> <span class=identifier>phone_number</span><span class=special>;</span>
<span class=identifier>phonebook_entry</span><span class=special>(</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span> <span class=identifier>family_name</span><span class=special>,</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span> <span class=identifier>given_name</span><span class=special>,</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span> <span class=identifier>phone_number</span><span class=special>):</span>
<span class=identifier>family_name</span><span class=special>(</span><span class=identifier>family_name</span><span class=special>),</span><span class=identifier>given_name</span><span class=special>(</span><span class=identifier>given_name</span><span class=special>),</span><span class=identifier>phone_number</span><span class=special>(</span><span class=identifier>phone_number</span><span class=special>)</span>
<span class=special>{}</span>
<span class=special>};</span>
<span class=comment>// define a multi_index_container with a composite key on
// (family_name,given_name)</span>
<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special>&lt;</span>
<span class=identifier>phonebook_entry</span><span class=special>,</span>
<span class=identifier>indexed_by</span><span class=special>&lt;</span>
<span class=comment>//non-unique as some subscribers might have more than one number</span>
<span class=identifier>ordered_non_unique</span><span class=special>&lt;</span>
<span class=identifier>composite_key</span><span class=special>&lt;</span>
<span class=identifier>phonebook_entry</span><span class=special>,</span>
<span class=identifier>member</span><span class=special>&lt;</span><span class=identifier>phonebook_entry</span><span class=special>,</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>,&amp;</span><span class=identifier>phonebook_entry</span><span class=special>::</span><span class=identifier>family_name</span><span class=special>&gt;,</span>
<span class=identifier>member</span><span class=special>&lt;</span><span class=identifier>phonebook_entry</span><span class=special>,</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>,&amp;</span><span class=identifier>phonebook_entry</span><span class=special>::</span><span class=identifier>given_name</span><span class=special>&gt;</span>
<span class=special>&gt;</span>
<span class=special>&gt;,</span>
<span class=identifier>ordered_unique</span><span class=special>&lt;</span> <span class=comment>// unique as numbers belong to only one subscriber</span>
<span class=identifier>member</span><span class=special>&lt;</span><span class=identifier>phonebook_entry</span><span class=special>,</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>,&amp;</span><span class=identifier>phonebook_entry</span><span class=special>::</span><span class=identifier>phone_number</span><span class=special>&gt;</span>
<span class=special>&gt;</span>
<span class=special>&gt;</span>
<span class=special>&gt;</span> <span class=identifier>phonebook</span><span class=special>;</span>
</pre></blockquote>
<p>
<code>composite_key</code> accepts two or more key extractors on the same
value (here, <code>phonebook_entry</code>). Lookup operations on a composite
key are accomplished by passing tuples with the values searched:
</p>
<blockquote><pre>
<span class=identifier>phonebook</span> <span class=identifier>pb</span><span class=special>;</span>
<span class=special>...</span>
<span class=comment>// search for Dorothea White's number</span>
<span class=identifier>phonebook</span><span class=special>::</span><span class=identifier>iterator</span> <span class=identifier>it</span><span class=special>=</span><span class=identifier>pb</span><span class=special>.</span><span class=identifier>find</span><span class=special>(</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>make_tuple</span><span class=special>(</span><span class=string>&quot;White&quot;</span><span class=special>,</span><span class=string>&quot;Dorothea&quot;</span><span class=special>));</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span> <span class=identifier>number</span><span class=special>=</span><span class=identifier>it</span><span class=special>-&gt;</span><span class=identifier>phone_number</span><span class=special>;</span>
</pre></blockquote>
<p>
Composite keys are sorted by lexicographical order, i.e. sorting is performed
by the first key, then the second key if the first one is equal, etc. This
order allows for partial searches where only the first keys are specified:
</p>
<blockquote><pre>
<span class=identifier>phonebook</span> <span class=identifier>pb</span><span class=special>;</span>
<span class=special>...</span>
<span class=comment>// look for all Whites</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>pair</span><span class=special>&lt;</span><span class=identifier>phonebook</span><span class=special>::</span><span class=identifier>iterator</span><span class=special>,</span><span class=identifier>phonebook</span><span class=special>::</span><span class=identifier>iterator</span><span class=special>&gt;</span> <span class=identifier>p</span><span class=special>=</span>
<span class=identifier>pb</span><span class=special>.</span><span class=identifier>equal_range</span><span class=special>(</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>make_tuple</span><span class=special>(</span><span class=string>&quot;White&quot;</span><span class=special>));</span>
</pre></blockquote>
<p>
As a notational convenience, when only the first key is specified it is possible
to pass the argument directly without including it into a tuple:
</p>
<blockquote><pre>
<span class=identifier>phonebook</span> <span class=identifier>pb</span><span class=special>;</span>
<span class=special>...</span>
<span class=comment>// look for all Whites</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>pair</span><span class=special>&lt;</span><span class=identifier>phonebook</span><span class=special>::</span><span class=identifier>iterator</span><span class=special>,</span><span class=identifier>phonebook</span><span class=special>::</span><span class=identifier>iterator</span><span class=special>&gt;</span> <span class=identifier>p</span><span class=special>=</span><span class=identifier>pb</span><span class=special>.</span><span class=identifier>equal_range</span><span class=special>(</span><span class=string>&quot;White&quot;</span><span class=special>);</span>
</pre></blockquote>
<p>
On the other hand, partial searches without specifying the first keys are not
allowed.
</p>
<p>
By default, the corresponding <code>std::less</code> predicate is used
for each subkey of a composite key. Alternate comparison predicates can
be specified with <a href="../reference/key_extraction.html#composite_key_compare">
<code>composite_key_compare</code></a>:
</p>
<blockquote><pre>
<span class=comment>// phonebook with given names in reverse order</span>
<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special>&lt;</span>
<span class=identifier>phonebook_entry</span><span class=special>,</span>
<span class=identifier>indexed_by</span><span class=special>&lt;</span>
<span class=identifier>ordered_non_unique</span><span class=special>&lt;</span>
<span class=identifier>composite_key</span><span class=special>&lt;</span>
<span class=identifier>phonebook_entry</span><span class=special>,</span>
<span class=identifier>member</span><span class=special>&lt;</span><span class=identifier>phonebook_entry</span><span class=special>,</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>,&amp;</span><span class=identifier>phonebook_entry</span><span class=special>::</span><span class=identifier>family_name</span><span class=special>&gt;,</span>
<span class=identifier>member</span><span class=special>&lt;</span><span class=identifier>phonebook_entry</span><span class=special>,</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>,&amp;</span><span class=identifier>phonebook_entry</span><span class=special>::</span><span class=identifier>given_name</span><span class=special>&gt;</span>
<span class=special>&gt;,</span>
<span class=identifier>composite_key_compare</span><span class=special>&lt;</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>less</span><span class=special>&lt;</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>&gt;,</span> <span class=comment>// family names sorted as by default</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>greater</span><span class=special>&lt;</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>&gt;</span> <span class=comment>// given names reversed</span>
<span class=special>&gt;</span>
<span class=special>&gt;,</span>
<span class=identifier>ordered_unique</span><span class=special>&lt;</span>
<span class=identifier>member</span><span class=special>&lt;</span><span class=identifier>phonebook_entry</span><span class=special>,</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>,&amp;</span><span class=identifier>phonebook_entry</span><span class=special>::</span><span class=identifier>phone_number</span><span class=special>&gt;</span>
<span class=special>&gt;</span>
<span class=special>&gt;</span>
<span class=special>&gt;</span> <span class=identifier>phonebook</span><span class=special>;</span>
</pre></blockquote>
<p>
See <a href="../examples.html#example7">example 7</a> in the examples section
for an application of <code>composite_key</code>.
</p>
<h3><a name="composite_keys_hash">Composite keys and hashed indices</a></h3>
<p>
Composite keys can also be used with hashed indices in a straightforward manner:
</p>
<blockquote><pre>
<span class=keyword>struct</span> <span class=identifier>street_entry</span>
<span class=special>{</span>
<span class=comment>// quadrant coordinates</span>
<span class=keyword>int</span> <span class=identifier>x</span><span class=special>;</span>
<span class=keyword>int</span> <span class=identifier>y</span><span class=special>;</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span> <span class=identifier>name</span><span class=special>;</span>
<span class=identifier>street_entry</span><span class=special>(</span><span class=keyword>int</span> <span class=identifier>x</span><span class=special>,</span><span class=keyword>int</span> <span class=identifier>y</span><span class=special>,</span><span class=keyword>const</span> <span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>&amp;</span> <span class=identifier>name</span><span class=special>):</span><span class=identifier>x</span><span class=special>(</span><span class=identifier>x</span><span class=special>),</span><span class=identifier>y</span><span class=special>(</span><span class=identifier>y</span><span class=special>),</span><span class=identifier>name</span><span class=special>(</span><span class=identifier>name</span><span class=special>){}</span>
<span class=special>};</span>
<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special>&lt;</span>
<span class=identifier>street_entry</span><span class=special>,</span>
<span class=identifier>indexed_by</span><span class=special>&lt;</span>
<span class=identifier>hashed_non_unique</span><span class=special>&lt;</span> <span class=comment>// indexed by quadrant coordinates</span>
<span class=identifier>composite_key</span><span class=special>&lt;</span>
<span class=identifier>street_entry</span><span class=special>,</span>
<span class=identifier>member</span><span class=special>&lt;</span><span class=identifier>street_entry</span><span class=special>,</span><span class=keyword>int</span><span class=special>,&amp;</span><span class=identifier>street_entry</span><span class=special>::</span><span class=identifier>x</span><span class=special>&gt;,</span>
<span class=identifier>member</span><span class=special>&lt;</span><span class=identifier>street_entry</span><span class=special>,</span><span class=keyword>int</span><span class=special>,&amp;</span><span class=identifier>street_entry</span><span class=special>::</span><span class=identifier>y</span><span class=special>&gt;</span>
<span class=special>&gt;</span>
<span class=special>&gt;,</span>
<span class=identifier>hashed_non_unique</span><span class=special>&lt;</span> <span class=comment>// indexed by street name</span>
<span class=identifier>member</span><span class=special>&lt;</span><span class=identifier>street_entry</span><span class=special>,</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>,&amp;</span><span class=identifier>street_entry</span><span class=special>::</span><span class=identifier>name</span><span class=special>&gt;</span>
<span class=special>&gt;</span>
<span class=special>&gt;</span>
<span class=special>&gt;</span> <span class=identifier>street_locator</span><span class=special>;</span>
<span class=identifier>street_locator</span> <span class=identifier>sl</span><span class=special>;</span>
<span class=special>...</span>
<span class=keyword>void</span> <span class=identifier>streets_in_quadrant</span><span class=special>(</span><span class=keyword>int</span> <span class=identifier>x</span><span class=special>,</span><span class=keyword>int</span> <span class=identifier>y</span><span class=special>)</span>
<span class=special>{</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>pair</span><span class=special>&lt;</span><span class=identifier>street_locator</span><span class=special>::</span><span class=identifier>iterator</span><span class=special>,</span><span class=identifier>street_locator</span><span class=special>::</span><span class=identifier>iterator</span><span class=special>&gt;</span> <span class=identifier>p</span><span class=special>=</span>
<span class=identifier>sl</span><span class=special>.</span><span class=identifier>equal_range</span><span class=special>(</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>make_tuple</span><span class=special>(</span><span class=identifier>x</span><span class=special>,</span><span class=identifier>y</span><span class=special>));</span>
<span class=keyword>while</span><span class=special>(</span><span class=identifier>p</span><span class=special>.</span><span class=identifier>first</span><span class=special>!=</span><span class=identifier>p</span><span class=special>.</span><span class=identifier>second</span><span class=special>){</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>cout</span><span class=special>&lt;&lt;</span><span class=identifier>p</span><span class=special>.</span><span class=identifier>first</span><span class=special>-&gt;</span><span class=identifier>name</span><span class=special>&lt;&lt;</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>endl</span><span class=special>;</span>
<span class=special>++</span><span class=identifier>p</span><span class=special>.</span><span class=identifier>first</span><span class=special>;</span>
<span class=special>}</span>
<span class=special>}</span>
</pre></blockquote>
<p>
Note that hashing is automatically taken care of: <code>boost::hash</code> is
specialized to hash a composite key as a function of the <code>boost::hash</code>
values of its elements. Should we need to specify different hash functions for the
elements of a composite key, we can explicitly do so by using the
<a href="../reference/key_extraction.html#composite_key_hash"><code>composite_key_hash</code></a>
utility:
</p>
<blockquote><pre>
<span class=keyword>struct</span> <span class=identifier>tuned_int_hash</span>
<span class=special>{</span>
<span class=keyword>int</span> <span class=keyword>operator</span><span class=special>()(</span><span class=keyword>int</span> <span class=identifier>x</span><span class=special>)</span><span class=keyword>const</span>
<span class=special>{</span>
<span class=comment>// specially tuned hash for this application</span>
<span class=special>}</span>
<span class=special>};</span>
<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special>&lt;</span>
<span class=identifier>street_entry</span><span class=special>,</span>
<span class=identifier>indexed_by</span><span class=special>&lt;</span>
<span class=identifier>hashed_non_unique</span><span class=special>&lt;</span> <span class=comment>// indexed by quadrant coordinates</span>
<span class=identifier>composite_key</span><span class=special>&lt;</span>
<span class=identifier>street_entry</span><span class=special>,</span>
<span class=identifier>member</span><span class=special>&lt;</span><span class=identifier>street_entry</span><span class=special>,</span><span class=keyword>int</span><span class=special>,&amp;</span><span class=identifier>street_entry</span><span class=special>::</span><span class=identifier>x</span><span class=special>&gt;,</span>
<span class=identifier>member</span><span class=special>&lt;</span><span class=identifier>street_entry</span><span class=special>,</span><span class=keyword>int</span><span class=special>,&amp;</span><span class=identifier>street_entry</span><span class=special>::</span><span class=identifier>y</span><span class=special>&gt;</span>
<span class=special>&gt;,</span>
<span class=identifier>composite_key_hash</span><span class=special>&lt;</span>
<span class=identifier>tuned_int_hash</span><span class=special>,</span>
<span class=identifier>tuned_int_hash</span>
<span class=special>&gt;</span>
<span class=special>&gt;,</span>
<span class=identifier>hashed_non_unique</span><span class=special>&lt;</span> <span class=comment>// indexed by street name</span>
<span class=identifier>member</span><span class=special>&lt;</span><span class=identifier>street_entry</span><span class=special>,</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>,&amp;</span><span class=identifier>street_entry</span><span class=special>::</span><span class=identifier>name</span><span class=special>&gt;</span>
<span class=special>&gt;</span>
<span class=special>&gt;</span>
<span class=special>&gt;</span> <span class=identifier>street_locator</span><span class=special>;</span>
</pre></blockquote>
<p>
Also, equality of composite keys can be tuned with
<a href="../reference/key_extraction.html#composite_key_equal_to"><code>composite_key_equal_to</code></a>,
though in most cases the default equality predicate (relying on
the <code>std::equal_to</code> instantiations for the element types)
will be the right choice.
</p>
<p>
Unlike with ordered indices, we cannot perform partial searches specifying
only the first elements of a composite key:
</p>
<blockquote><pre>
<span class=comment>// try to locate streets in quadrants with x==0
// compile-time error: hashed indices do not allow such operations</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>pair</span><span class=special>&lt;</span><span class=identifier>street_locator</span><span class=special>::</span><span class=identifier>iterator</span><span class=special>,</span><span class=identifier>street_locator</span><span class=special>::</span><span class=identifier>iterator</span><span class=special>&gt;</span> <span class=identifier>p</span><span class=special>=</span>
<span class=identifier>sl</span><span class=special>.</span><span class=identifier>equal_range</span><span class=special>(</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>make_tuple</span><span class=special>(</span><span class=number>0</span><span class=special>));</span>
</pre></blockquote>
<p>
The reason for this limitation is quite logical: as the hash value of a composite
key depends on all of its elements, it is impossible to calculate it from
partial information.
</p>
<h2><a name="advanced_key_extractors">Advanced features of Boost.MultiIndex key
extractors</a></h2>
<p>
The <a href="../reference/key_extraction.html#key_extractors"><code>Key Extractor</code></a>
concept allows the same object to extract keys from several different types,
possibly through suitably defined overloads of <code>operator()</code>:
</p>
<blockquote><pre>
<span class=comment>// example of a name extractor from employee and employee *</span>
<span class=keyword>struct</span> <span class=identifier>name_extractor</span>
<span class=special>{</span>
<span class=keyword>typedef</span> <span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span> <span class=identifier>result_type</span><span class=special>;</span>
<span class=keyword>const</span> <span class=identifier>result_type</span><span class=special>&amp;</span> <span class=keyword>operator</span><span class=special>()(</span><span class=keyword>const</span> <span class=identifier>employee</span><span class=special>&amp;</span> <span class=identifier>e</span><span class=special>)</span><span class=keyword>const</span><span class=special>{</span><span class=keyword>return</span> <span class=identifier>e</span><span class=special>.</span><span class=identifier>name</span><span class=special>;}</span>
<span class=identifier>result_type</span><span class=special>&amp;</span> <span class=keyword>operator</span><span class=special>()(</span><span class=identifier>employee</span><span class=special>*</span> <span class=identifier>e</span><span class=special>)</span><span class=keyword>const</span><span class=special>{</span><span class=keyword>return</span> <span class=identifier>e</span><span class=special>-&gt;</span><span class=identifier>name</span><span class=special>;}</span>
<span class=special>};</span>
<span class=comment>// name_extractor can handle elements of type employee...</span>
<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special>&lt;</span>
<span class=identifier>employee</span><span class=special>,</span>
<span class=identifier>indexed_by</span><span class=special>&lt;</span>
<span class=identifier>ordered_unique</span><span class=special>&lt;</span><span class=identifier>name_extractor</span><span class=special>&gt;</span>
<span class=special>&gt;</span>
<span class=special>&gt;</span> <span class=identifier>employee_set</span><span class=special>;</span>
<span class=comment>// ...as well as elements of type employee *</span>
<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special>&lt;</span>
<span class=identifier>employee</span><span class=special>*,</span>
<span class=identifier>indexed_by</span><span class=special>&lt;</span>
<span class=identifier>ordered_unique</span><span class=special>&lt;</span><span class=identifier>name_extractor</span><span class=special>&gt;</span>
<span class=special>&gt;</span>
<span class=special>&gt;</span> <span class=identifier>employee_ptr_set</span><span class=special>;</span>
</pre></blockquote>
<p>
This possibility is fully exploited by predefined key extractors provided
by Boost.MultiIndex, making it simpler to define <code>multi_index_container</code>s
where elements are pointers or references to the actual objects. The following
specifies a <code>multi_index_container</code> of pointers to employees sorted by their
names.
</p>
<blockquote><pre>
<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special>&lt;</span>
<span class=identifier>employee</span> <span class=special>*,</span>
<span class=identifier>indexed_by</span><span class=special>&lt;</span>
<span class=identifier>ordered_non_unique</span><span class=special>&lt;</span><span class=identifier>member</span><span class=special>&lt;</span><span class=identifier>employee</span><span class=special>,</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>,&amp;</span><span class=identifier>employee</span><span class=special>::</span><span class=identifier>name</span><span class=special>&gt;</span> <span class=special>&gt;</span> <span class=special>&gt;</span>
<span class=special>&gt;</span> <span class=identifier>employee_set</span><span class=special>;</span>
</pre></blockquote>
<p>
Note that this is specified in exactly the same manner as a <code>multi_index_container</code>
of actual <code>employee</code> objects: <code>member</code> takes care of the
extra dereferencing needed to gain access to <code>employee::name</code>. A similar
functionality is provided for interoperability with reference wrappers from
<a href="../../../../doc/html/ref.html">Boost.Ref</a>:
</p>
<blockquote><pre>
<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special>&lt;</span>
<span class=identifier>boost</span><span class=special>::</span><span class=identifier>reference_wrapper</span><span class=special>&lt;</span><span class=keyword>const</span> <span class=identifier>employee</span><span class=special>&gt;,</span>
<span class=identifier>indexed_by</span><span class=special>&lt;</span>
<span class=identifier>ordered_non_unique</span><span class=special>&lt;</span><span class=identifier>member</span><span class=special>&lt;</span><span class=identifier>employee</span><span class=special>,</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>,&amp;</span><span class=identifier>employee</span><span class=special>::</span><span class=identifier>name</span><span class=special>&gt;</span> <span class=special>&gt;</span> <span class=special>&gt;</span>
<span class=special>&gt;</span> <span class=identifier>employee_set</span><span class=special>;</span>
</pre></blockquote>
<p>
In fact, support for pointers is further extended to accept what we call
<i>chained pointers</i>. Such a chained pointer is defined by induction as a raw or
smart pointer or iterator to the actual element, to a reference wrapper of the
element or <i>to another chained pointer</i>; that is, chained pointers are arbitrary
compositions of pointer-like types ultimately dereferencing
to the element from where the key is to be extracted. Examples of chained
pointers to <code>employee</code> are:
<ul>
<li><code>employee *</code>,</li>
<li><code>const employee *</code>,</li>
<li><code>std::unique_ptr&lt;employee></code>,</li>
<li><code>std::list&lt;boost::reference_wrapper&lt;employee> >::iterator</code>,</li>
<li><code>employee **</code>,</li>
<li><code>boost::shared_ptr&lt;const employee *></code>.</li>
</ul>
In general, chained pointers with dereferencing distance greater than 1 are not
likely to be used in a normal program, but they can arise in frameworks
which construct "views" as <code>multi_index_container</code>s from preexisting
<code>multi_index_container</code>s.
</p>
<p>
In order to present a short summary of the different usages of Boost.MultiIndex
key extractors in the presence of reference wrappers and pointers, consider the
following final type:
</p>
<blockquote><pre>
<span class=keyword>struct</span> <span class=identifier>T</span>
<span class=special>{</span>
<span class=keyword>int</span> <span class=identifier>i</span><span class=special>;</span>
<span class=keyword>const</span> <span class=keyword>int</span> <span class=identifier>j</span><span class=special>;</span>
<span class=keyword>int</span> <span class=identifier>f</span><span class=special>()</span><span class=keyword>const</span><span class=special>;</span>
<span class=keyword>int</span> <span class=identifier>g</span><span class=special>();</span>
<span class=keyword>static</span> <span class=keyword>int</span> <span class=identifier>gf</span><span class=special>(</span><span class=keyword>const</span> <span class=identifier>T</span><span class=special>&amp;);</span>
<span class=keyword>static</span> <span class=keyword>int</span> <span class=identifier>gg</span><span class=special>(</span><span class=identifier>T</span><span class=special>&amp;);</span>
<span class=special>};</span>
</pre></blockquote>
<p>
The table below lists the appropriate key extractors to be used for
different pointer and reference wrapper types based on <code>T</code>, for
each of its members.
</p>
<p align="center">
<table cellspacing="0">
<caption><b>Use cases for Boost.MultiIndex key extractors.</b></caption>
<tr>
<th>element type</th>
<th>&nbsp;key&nbsp;</th>
<th>key extractor</th>
<th>applicable to<br><code>const</code> elements?</th>
<th>read/write?</th>
</tr>
<tr>
<td align="center" rowspan="6"><code>T</code></td>
<td><code>i</code></td>
<td><code>member&lt;T,int,&amp;T::i></code></td>
<td align="center">yes</td>
<td align="center">yes</td>
</tr>
<tr>
<td><code>j</code></td>
<td><code>member&lt;T,const int,&amp;T::j></code></td>
<td align="center">yes</td>
<td align="center">no</td>
</tr>
<tr>
<td><code>f()</code></td>
<td><code>const_mem_fun&lt;T,int,&amp;T::f></code></td>
<td align="center">yes</td>
<td align="center">no</td>
</tr>
<tr>
<td><code>g()</code></td>
<td><code>mem_fun&lt;T,int,&amp;T::g></code></td>
<td align="center">no</td>
<td align="center">no</td>
</tr>
<tr>
<td><code>gf()</code></td>
<td><code>global_fun&lt;const T&amp;,int,&amp;T::gf></code></td>
<td align="center">yes</td>
<td align="center">no</td>
</tr>
<tr>
<td><code>gg()</code></td>
<td><code>global_fun&lt;T&amp;,int,&amp;T::gg></code></td>
<td align="center">no</td>
<td align="center">no</td>
</tr>
<tr class="odd_tr">
<td align="center" rowspan="6"><code>reference_wrapper&lt;T></code></td>
<td><code>i</code></td>
<td><code>member&lt;T,int,&amp;T::i></code></td>
<td align="center">yes</td>
<td align="center">yes</td>
</tr>
<tr class="odd_tr">
<td><code>j</code></td>
<td><code>member&lt;T,const int,&amp;T::j></code></td>
<td align="center">yes</td>
<td align="center">no</td>
</tr>
<tr class="odd_tr">
<td><code>f()</code></td>
<td><code>const_mem_fun&lt;T,int,&amp;T::f></code></td>
<td align="center">yes</td>
<td align="center">no</td>
</tr>
<tr class="odd_tr">
<td><code>g()</code></td>
<td><code>mem_fun&lt;T,int,&amp;T::g></code></td>
<td align="center">yes</td>
<td align="center">no</td>
</tr>
<tr class="odd_tr">
<td><code>gf()</code></td>
<td><code>global_fun&lt;const T&amp;,int,&amp;T::gf></code></td>
<td align="center">yes</td>
<td align="center">no</td>
</tr>
<tr class="odd_tr">
<td><code>gg()</code></td>
<td><code>global_fun&lt;T&amp;,int,&amp;T::gg></code></td>
<td align="center">yes</td>
<td align="center">no</td>
</tr>
<tr>
<td align="center" rowspan="6"><code>reference_wrapper&lt;const T></code></td>
<td><code>i</code></td>
<td><code>member&lt;T,const int,&amp;T::i></code></td>
<td align="center">yes</td>
<td align="center">no</td>
</tr>
<tr>
<td><code>j</code></td>
<td><code>member&lt;T,const int,&amp;T::j></code></td>
<td align="center">yes</td>
<td align="center">no</td>
</tr>
<tr>
<td><code>f()</code></td>
<td><code>const_mem_fun&lt;T,int,&amp;T::f></code></td>
<td align="center">yes</td>
<td align="center">no</td>
</tr>
<tr>
<td><code>g()</code></td>
<td colspan="3">&nbsp;</td>
</tr>
<tr>
<td><code>gf()</code></td>
<td><code>global_fun&lt;const T&amp;,int,&amp;T::gf></code></td>
<td align="center">yes</td>
<td align="center">no</td>
</tr>
<tr>
<td><code>gg()</code></td>
<td colspan="3">&nbsp;</td>
</tr>
<tr class="odd_tr">
<td align="center" rowspan="6">chained pointer to <code>T</code><br>
or to <code>reference_wrapper&lt;T></code></td>
<td><code>i</code></td>
<td><code>member&lt;T,int,&amp;T::i></code></td>
<td align="center">yes</td>
<td align="center">yes</td>
</tr>
<tr class="odd_tr">
<td><code>j</code></td>
<td><code>member&lt;T,const int,&amp;T::j></code></td>
<td align="center">yes</td>
<td align="center">no</td>
</tr>
<tr class="odd_tr">
<td><code>f()</code></td>
<td><code>const_mem_fun&lt;T,int,&amp;T::f></code></td>
<td align="center">yes</td>
<td align="center">no</td>
</tr>
<tr class="odd_tr">
<td><code>g()</code></td>
<td><code>mem_fun&lt;T,int,&amp;T::g></code></td>
<td align="center">yes</td>
<td align="center">no</td>
</tr>
<tr class="odd_tr">
<td><code>gf()</code></td>
<td><code>global_fun&lt;const T&amp;,int,&amp;T::gf></code></td>
<td align="center">yes</td>
<td align="center">no</td>
</tr>
<tr class="odd_tr">
<td><code>gg()</code></td>
<td><code>global_fun&lt;T&amp;,int,&amp;T::gg></code></td>
<td align="center">yes</td>
<td align="center">no</td>
</tr>
<tr>
<td align="center" rowspan="6">chained pointer to <code>const T</code><br>
or to <code>reference_wrapper&lt;const T></code></td>
<td><code>i</code></td>
<td><code>member&lt;T,const int,&amp;T::i></code></td>
<td align="center">yes</td>
<td align="center">no</td>
</tr>
<tr>
<td><code>j</code></td>
<td><code>member&lt;T,const int,&amp;T::j></code></td>
<td align="center">yes</td>
<td align="center">no</td>
</tr>
<tr>
<td><code>f()</code></td>
<td><code>const_mem_fun&lt;T,int,&amp;T::f></code></td>
<td align="center">yes</td>
<td align="center">no</td>
</tr>
<tr>
<td><code>g()</code></td>
<td colspan="3">&nbsp;</td>
</tr>
<tr>
<td><code>gf()</code></td>
<td><code>global_fun&lt;const T&amp;,int,&amp;T::gf></code></td>
<td align="center">yes</td>
<td align="center">no</td>
</tr>
<tr>
<td><code>gg()</code></td>
<td colspan="3">&nbsp;</td>
</tr>
</table>
</p>
<p>
The column "applicable to <code>const</code> elements?" states whether the
corresponding key extractor can be used when passed constant elements (this
relates to the elements specified in the first column, not the referenced
<code>T</code> objects). The only negative cases are for <code>T::g</code> and
<code>T:gg</code> when the elements are raw <code>T</code> objects, which make sense
as we are dealing with a non-constant member function (<code>T::g</code>)
and a function taking <code>T</code> by
non-constant reference: this also implies that <code>multi_index_container</code>s
of elements of <code>T</code> cannot be sorted by <code>T::g</code> or <code>T::gg</code>, because
elements contained within a <code>multi_index_container</code> are treated as constant.
</p>
<p>
The column "read/write?" shows which combinations yield
<a href="#read_write_key_extractors">read/write key extractors</a>.
</p>
<p>
Some care has to be taken to preserve <code>const</code>-correctness in the
specification of <code>member</code> key extractors: in some sense, the <code>const</code>
qualifier is carried along to the member part, even if that particular
member is not defined as <code>const</code>. For instance, if the elements
are of type <code>const T *</code>, sorting by <code>T::i</code> is <i>not</i>
specified as <code>member&lt;const T,int,&amp;T::i></code>, but rather as
<code>member&lt;T,const int,&amp;T::i></code>.
</p>
<p>
For practical demonstrations of use of these key extractors, refer to
<a href="../examples.html#example2">example 2</a> and
<a href="../examples.html#example6">example 6</a> in the examples section.
</p>
<hr>
<div class="prev_link"><a href="indices.html"><img src="../prev.gif" alt="index types" border="0"><br>
Index types
</a></div>
<div class="up_link"><a href="index.html"><img src="../up.gif" alt="Boost.MultiIndex tutorial" border="0"><br>
Boost.MultiIndex tutorial
</a></div>
<div class="next_link"><a href="creation.html"><img src="../next.gif" alt="container creation" border="0"><br>
Container creation
</a></div><br clear="all" style="clear: all;">
<br>
<p>Revised March 25th 2015</p>
<p>&copy; Copyright 2003-2015 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz.
Distributed under the Boost Software
License, Version 1.0. (See accompanying file <a href="../../../../LICENSE_1_0.txt">
LICENSE_1_0.txt</a> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">
http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

View File

@@ -0,0 +1,405 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0.1 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Boost.MultiIndex Documentation - Tutorial - Techniques</title>
<link rel="stylesheet" href="../style.css" type="text/css">
<link rel="start" href="../index.html">
<link rel="prev" href="debug.html">
<link rel="up" href="index.html">
<link rel="next" href="../reference/index.html">
</head>
<body>
<h1><img src="../../../../boost.png" alt="boost.png (6897 bytes)" align=
"middle" width="277" height="86">Boost.MultiIndex Tutorial: Techniques</h1>
<div class="prev_link"><a href="debug.html"><img src="../prev.gif" alt="debugging support" border="0"><br>
Debugging support
</a></div>
<div class="up_link"><a href="index.html"><img src="../up.gif" alt="Boost.MultiIndex tutorial" border="0"><br>
Boost.MultiIndex tutorial
</a></div>
<div class="next_link"><a href="../reference/index.html"><img src="../next.gif" alt="Boost.MultiIndex reference" border="0"><br>
Boost.MultiIndex reference
</a></div><br clear="all" style="clear: all;">
<hr>
<h2>Contents</h2>
<ul>
<li><a href="#emulate_std_containers">Emulating standard containers with
<code>multi_index_container</code></a>
<ul>
<li><a href="#emulate_assoc_containers">Emulation of associative
containers</a></li>
<li><a href="#emulate_std_list">Emulation of <code>std::list</code></a></li>
</ul>
</li>
<li><a href="#metaprogrammming">Metaprogramming and <code>multi_index_container</code></a>
<ul>
<li><a href="#mpl_analysis">MPL analysis</a></li>
<li><a href="#mpl_synthesis">MPL synthesis</a></li>
</ul>
</li>
</ul>
<h2><a name="emulate_std_containers">Emulating standard containers with
<code>multi_index_container</code></a></h2>
<h3><a name="emulate_assoc_containers">Emulation of associative
containers</a></h3>
<p>
Academic movitations aside, there is a practical interest in emulating standard
associative containers by means of <code>multi_index_container</code>, namely to take
advantage of extended functionalities provided by <code>multi_index_container</code> for
lookup, range querying and updating.
</p>
<p>
In order to emulate a <code>std::set</code> one can follow the substitution
rule:
</p>
<blockquote><pre>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>set</span><span class=special>&lt;</span><span class=identifier>Key</span><span class=special>,</span><span class=identifier>Compare</span><span class=special>,</span><span class=identifier>Allocator</span><span class=special>&gt;</span> <span class=special>-&gt;</span>
<span class=identifier>multi_index_container</span><span class=special>&lt;</span>
<span class=identifier>Key</span><span class=special>,</span>
<span class=identifier>indexed_by</span><span class=special>&lt;</span><span class=identifier>ordered_unique</span><span class=special>&lt;</span><span class=identifier>identity</span><span class=special>&lt;</span><span class=identifier>Key</span><span class=special>&gt;,</span><span class=identifier>Compare</span><span class=special>&gt;</span> <span class=special>&gt;,</span>
<span class=identifier>Allocator</span>
<span class=special>&gt;</span>
</pre></blockquote>
<p>
In the default case where <code>Compare=std::less&lt;Key></code> and
<code>Allocator=std::allocator&lt;Key></code>, the substitution rule is
simplified as
</p>
<blockquote><pre>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>set</span><span class=special>&lt;</span><span class=identifier>Key</span><span class=special>&gt;</span> <span class=special>-&gt;</span> <span class=identifier>multi_index_container</span><span class=special>&lt;</span><span class=identifier>Key</span><span class=special>&gt;</span>
</pre></blockquote>
<p>
The substitution of <code>multi_index_container</code> for <code>std::set</code> keeps
the whole set of functionality provided by <code>std::set</code>, so in
principle it is a drop-in replacement needing no further adjustments.
</p>
<p>
<code>std::multiset</code> can be emulated in a similar manner, according to the
following rule:
</p>
<blockquote><pre>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>multiset</span><span class=special>&lt;</span><span class=identifier>Key</span><span class=special>,</span><span class=identifier>Compare</span><span class=special>,</span><span class=identifier>Allocator</span><span class=special>&gt;</span> <span class=special>-&gt;</span>
<span class=identifier>multi_index_container</span><span class=special>&lt;</span>
<span class=identifier>Key</span><span class=special>,</span>
<span class=identifier>indexed_by</span><span class=special>&lt;</span><span class=identifier>ordered_non_unique</span><span class=special>&lt;</span><span class=identifier>identity</span><span class=special>&lt;</span><span class=identifier>Key</span><span class=special>&gt;,</span><span class=identifier>Compare</span><span class=special>&gt;</span> <span class=special>&gt;,</span>
<span class=identifier>Allocator</span>
<span class=special>&gt;</span>
</pre></blockquote>
<p>
When default values are taken into consideration, the rule takes the form
</p>
<blockquote><pre>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>multiset</span><span class=special>&lt;</span><span class=identifier>Key</span><span class=special>&gt;</span> <span class=special>-&gt;</span>
<span class=identifier>multi_index_container</span><span class=special>&lt;</span>
<span class=identifier>Key</span><span class=special>,</span>
<span class=identifier>indexed_by</span><span class=special>&lt;</span><span class=identifier>ordered_non_unique</span><span class=special>&lt;</span><span class=identifier>identity</span><span class=special>&lt;</span><span class=identifier>Key</span><span class=special>&gt;</span> <span class=special>&gt;</span> <span class=special>&gt;</span>
<span class=special>&gt;</span>
</pre></blockquote>
<p>
The emulation of <code>std::multiset</code>s with <code>multi_index_container</code>
results in a slight difference with respect to the interface offered: the member
function <code>insert(const value_type&amp;)</code> does not return an
<code>iterator</code> as in <code>std::multiset</code>s, but rather a
<code>std::pair&lt;iterator,bool></code> in the spirit of <code>std::set</code>s.
In this particular case, however, the <code>bool</code> member of the returned
pair is always <code>true</code>.
</p>
<p>
The case of <code>std::map</code>s and <code>std::multimap</code>s does not lend
itself to such a direct emulation by means of <code>multi_index_container</code>. The main
problem lies in the fact that elements of a <code>multi_index_container</code> are treated
as constant, while the <code>std::map</code> and <code>std::multimap</code> handle
objects of type <code>std::pair&lt;const Key,T></code>, thus allowing for free
modification of the value part. To overcome this difficulty we need to create an ad
hoc pair class:
</p>
<blockquote><pre>
<span class=keyword>template</span> <span class=special>&lt;</span><span class=keyword>typename</span> <span class=identifier>T1</span><span class=special>,</span><span class=keyword>typename</span> <span class=identifier>T2</span><span class=special>&gt;</span>
<span class=keyword>struct</span> <span class=identifier>mutable_pair</span>
<span class=special>{</span>
<span class=keyword>typedef</span> <span class=identifier>T1</span> <span class=identifier>first_type</span><span class=special>;</span>
<span class=keyword>typedef</span> <span class=identifier>T2</span> <span class=identifier>second_type</span><span class=special>;</span>
<span class=identifier>mutable_pair</span><span class=special>():</span><span class=identifier>first</span><span class=special>(</span><span class=identifier>T1</span><span class=special>()),</span><span class=identifier>second</span><span class=special>(</span><span class=identifier>T2</span><span class=special>()){}</span>
<span class=identifier>mutable_pair</span><span class=special>(</span><span class=keyword>const</span> <span class=identifier>T1</span><span class=special>&amp;</span> <span class=identifier>f</span><span class=special>,</span><span class=keyword>const</span> <span class=identifier>T2</span><span class=special>&amp;</span> <span class=identifier>s</span><span class=special>):</span><span class=identifier>first</span><span class=special>(</span><span class=identifier>f</span><span class=special>),</span><span class=identifier>second</span><span class=special>(</span><span class=identifier>s</span><span class=special>){}</span>
<span class=identifier>mutable_pair</span><span class=special>(</span><span class=keyword>const</span> <span class=identifier>std</span><span class=special>::</span><span class=identifier>pair</span><span class=special>&lt;</span><span class=identifier>T1</span><span class=special>,</span><span class=identifier>T2</span><span class=special>&gt;&amp;</span> <span class=identifier>p</span><span class=special>):</span><span class=identifier>first</span><span class=special>(</span><span class=identifier>p</span><span class=special>.</span><span class=identifier>first</span><span class=special>),</span><span class=identifier>second</span><span class=special>(</span><span class=identifier>p</span><span class=special>.</span><span class=identifier>second</span><span class=special>){}</span>
<span class=identifier>T1</span> <span class=identifier>first</span><span class=special>;</span>
<span class=keyword>mutable</span> <span class=identifier>T2</span> <span class=identifier>second</span><span class=special>;</span>
<span class=special>};</span>
</pre></blockquote>
<p>
and so the substitution rules are:
</p>
<blockquote><pre>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>map</span><span class=special>&lt;</span><span class=identifier>Key</span><span class=special>,</span><span class=identifier>T</span><span class=special>,</span><span class=identifier>Compare</span><span class=special>,</span><span class=identifier>Allocator</span><span class=special>&gt;</span> <span class=special>-&gt;</span>
<span class=identifier>multi_index_container</span><span class=special>&lt;</span>
<span class=identifier>Element</span><span class=special>,</span>
<span class=identifier>indexed_by</span><span class=special>&lt;</span>
<span class=identifier>ordered_unique</span><span class=special>&lt;</span><span class=identifier>member</span><span class=special>&lt;</span><span class=identifier>Element</span><span class=special>,</span><span class=identifier>Key</span><span class=special>,&amp;</span><span class=identifier>Element</span><span class=special>::</span><span class=identifier>first</span><span class=special>&gt;,</span><span class=identifier>Compare</span><span class=special>&gt;</span>
<span class=special>&gt;,</span>
<span class=keyword>typename</span> <span class=identifier>Allocator</span><span class=special>::</span><span class=keyword>template</span> <span class=identifier>rebind</span><span class=special>&lt;</span><span class=identifier>Element</span><span class=special>&gt;::</span><span class=identifier>other</span>
<span class=special>&gt;</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>multimap</span><span class=special>&lt;</span><span class=identifier>Key</span><span class=special>,</span><span class=identifier>T</span><span class=special>,</span><span class=identifier>Compare</span><span class=special>,</span><span class=identifier>Allocator</span><span class=special>&gt;</span> <span class=special>-&gt;</span>
<span class=identifier>multi_index_container</span><span class=special>&lt;</span>
<span class=identifier>Element</span><span class=special>,</span>
<span class=identifier>indexed_by</span><span class=special>&lt;</span>
<span class=identifier>ordered_non_unique</span><span class=special>&lt;</span><span class=identifier>member</span><span class=special>&lt;</span><span class=identifier>Element</span><span class=special>,</span><span class=identifier>Key</span><span class=special>,&amp;</span><span class=identifier>Element</span><span class=special>::</span><span class=identifier>first</span><span class=special>&gt;,</span><span class=identifier>Compare</span><span class=special>&gt;</span>
<span class=special>&gt;,</span>
<span class=keyword>typename</span> <span class=identifier>Allocator</span><span class=special>::</span><span class=keyword>template</span> <span class=identifier>rebind</span><span class=special>&lt;</span><span class=identifier>Element</span><span class=special>&gt;::</span><span class=identifier>other</span>
<span class=special>&gt;</span>
(<span class=identifier>with</span> <span class=identifier>Element</span><span class=special>=</span><span class=identifier>mutable_pair</span><span class=special>&lt;</span><span class=identifier>Key</span><span class=special>,</span><span class=identifier>T</span><span class=special>&gt;</span>)
</pre></blockquote>
<p>
If default values are considered, the rules take the form:
</p>
<blockquote><pre>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>map</span><span class=special>&lt;</span><span class=identifier>Key</span><span class=special>,</span><span class=identifier>T</span><span class=special>&gt;</span> <span class=special>-&gt;</span>
<span class=identifier>multi_index_container</span><span class=special>&lt;</span>
<span class=identifier>Element</span><span class=special>,
</span><span class=identifier>indexed_by</span><span class=special>&lt;</span><span class=identifier>ordered_unique</span><span class=special>&lt;</span><span class=identifier>member</span><span class=special>&lt;</span><span class=identifier>Element</span><span class=special>,</span><span class=identifier>Key</span><span class=special>,&amp;</span><span class=identifier>Element</span><span class=special>::</span><span class=identifier>first</span><span class=special>&gt;</span> <span class=special>&gt;</span> <span class=special>&gt;</span>
<span class=special>&gt;</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>multimap</span><span class=special>&lt;</span><span class=identifier>Key</span><span class=special>,</span><span class=identifier>T</span><span class=special>&gt;</span> <span class=special>-&gt;</span>
<span class=identifier>multi_index_container</span><span class=special>&lt;</span>
<span class=identifier>Element</span><span class=special>,
</span><span class=identifier>indexed_by</span><span class=special>&lt;</span><span class=identifier>ordered_non_unique</span><span class=special>&lt;</span><span class=identifier>member</span><span class=special>&lt;</span><span class=identifier>Element</span><span class=special>,</span><span class=identifier>Key</span><span class=special>,&amp;</span><span class=identifier>Element</span><span class=special>::</span><span class=identifier>first</span><span class=special>&gt;</span> <span class=special>&gt;</span> <span class=special>&gt;</span>
<span class=special>&gt;</span>
(<span class=identifier>with</span> <span class=identifier>Element</span><span class=special>=</span><span class=identifier>mutable_pair</span><span class=special>&lt;</span><span class=identifier>Key</span><span class=special>,</span><span class=identifier>T</span><span class=special>&gt;</span>)
</pre></blockquote>
<p>
Unlike as with standard sets, the interface of these <code>multi_index_container</code>-emulated
maps does not exactly conform to that of <code>std::map</code>s and
<code>std::multimap</code>s. The most obvious difference is the lack of
<code>operator []</code>, either in read or write mode; this, however, can be
emulated with appropriate use of <code>find</code> and <code>insert</code>.
</p>
<p>
These emulations of standard associative containers with <code>multi_index_container</code>
are comparable to the original constructs in terms of space and time efficiency.
See the <a href="../performance.html">performance section</a> for further details.
</p>
<h3><a name="emulate_std_list">Emulation of <code>std::list</code></a></h3>
<p>
Unlike the case of associative containers, emulating <code>std::list</code>
in Boost.MultiIndex does not add any significant functionality, so the following
is presented merely for completeness sake.
</p>
<p>
Much as with standard maps, the main difficulty to overcome when emulating
<code>std::list</code> derives from the constant nature of elements of a
<code>multi_index_container</code>. Again, some sort of adaption class is needed, like
for instance the following:
</p>
<blockquote><pre>
<span class=keyword>template</span> <span class=special>&lt;</span><span class=keyword>typename</span> <span class=identifier>T</span><span class=special>&gt;</span>
<span class=keyword>struct</span> <span class=identifier>mutable_value</span>
<span class=special>{</span>
<span class=identifier>mutable_value</span><span class=special>(</span><span class=keyword>const</span> <span class=identifier>T</span><span class=special>&amp;</span> <span class=identifier>t</span><span class=special>):</span><span class=identifier>t</span><span class=special>(</span><span class=identifier>t</span><span class=special>){}</span>
<span class=keyword>operator</span> <span class=identifier>T</span><span class=special>&amp;()</span><span class=keyword>const</span><span class=special>{</span><span class=keyword>return</span> <span class=identifier>t</span><span class=special>;}</span>
<span class=keyword>private</span><span class=special>:</span>
<span class=keyword>mutable</span> <span class=identifier>T</span> <span class=identifier>t</span><span class=special>;</span>
<span class=special>};</span>
</pre></blockquote>
<p>
which allows us to use the substitution rule:
</p>
<blockquote><pre>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>list</span><span class=special>&lt;</span><span class=identifier>T</span><span class=special>,</span><span class=identifier>Allocator</span><span class=special>&gt;</span> <span class=special>-&gt;</span>
<span class=identifier>multi_index_container</span><span class=special>&lt;</span>
<span class=identifier>Element</span><span class=special>,</span>
<span class=identifier>indexed_by</span><span class=special>&lt;</span><span class=identifier>sequenced</span><span class=special>&lt;&gt;</span> <span class=special>&gt;,</span>
<span class=keyword>typename</span> <span class=identifier>Allocator</span><span class=special>::</span><span class=keyword>template</span> <span class=identifier>rebind</span><span class=special>&lt;</span><span class=identifier>Element</span><span class=special>&gt;::</span><span class=identifier>other</span>
<span class=special>&gt;</span>
(<span class=identifier>with</span> <span class=identifier>Element</span><span class=special>=</span><span class=identifier>mutable_value</span><span class=special>&lt;</span><span class=identifier>T</span><span class=special>&gt;</span>)
</pre></blockquote>
<p>
or, if the default value <code>Allocator=std::allocator&lt;T></code> is used:
</p>
<blockquote><pre>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>list</span><span class=special>&lt;</span><span class=identifier>T</span><span class=special>&gt;</span> <span class=special>-&gt;</span>
<span class=identifier>multi_index_container</span><span class=special>&lt;</span><span class=identifier>mutable_value</span><span class=special>&lt;</span><span class=identifier>T</span><span class=special>&gt;,</span><span class=identifier>indexed_by</span><span class=special>&lt;</span><span class=identifier>sequenced</span><span class=special>&lt;&gt;</span> <span class=special>&gt;</span> <span class=special>&gt;</span>
</pre></blockquote>
<h2><a name="metaprogrammming">Metaprogramming and <code>multi_index_container</code></a></h2>
<p>
Boost.MultiIndex provides a number of facilities intended to allow the analysis and
synthesis of <code>multi_index_container</code> instantiations by
<a href="../../../../libs/mpl/doc/index.html">MPL</a> metaprograms.
</p>
<h3><a name="mpl_analysis">MPL analysis</a></h3>
<p>
Given a <code>multi_index_container</code> instantiation, the following nested types are
provided for compile-time inspection of the various types occurring in the
definition of the <code>multi_index_container</code>:
<ul>
<li><code>index_specifier_type_list</code>,</li>
<li><code>index_type_list</code>,</li>
<li><code>iterator_type_list</code>,</li>
<li><code>const_iterator_type_list</code>.</li>
</ul>
Each of these types is an MPL sequence with as many elements as indices
comprise the <code>multi_index_container</code>: for instance, the <code>n</code>-th
element of <code>iterator_type_list</code> is the same as
<code>nth_index&lt;n>::type::iterator</code>.
</p>
<p>
A subtle but important distinction exists between
<code>index_specifier_type_list</code> and <code>index_type_list</code>:
the former typelist holds the index <i>specifiers</i>
with which the <code>multi_index_container</code> instantiation was defined,
while the latter gives access to the actual implementation classes
corresponding to each specifier. An example will help to clarify
this distinction. Given the instantiation:
</p>
<blockquote><pre>
<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special>&lt;</span>
<span class=keyword>int</span><span class=special>,</span>
<span class=identifier>indexed_by</span><span class=special>&lt;</span>
<span class=identifier>ordered_unique</span><span class=special>&lt;</span><span class=identifier>identity</span><span class=special>&lt;</span><span class=keyword>int</span><span class=special>&gt;</span> <span class=special>&gt;,</span>
<span class=identifier>sequenced</span><span class=special>&lt;&gt;</span>
<span class=special>&gt;</span>
<span class=special>&gt;</span> <span class=identifier>indexed_t</span><span class=special>;</span>
</pre></blockquote>
<p>
<code>indexed_t::index_specifier_type_list</code> is a type list with
elements
</p>
<blockquote><pre>
<span class=identifier>ordered_unique</span><span class=special>&lt;</span><span class=identifier>identity</span><span class=special>&lt;</span><span class=keyword>int</span><span class=special>&gt;</span> <span class=special>&gt;</span>
<span class=identifier>sequenced</span><span class=special>&lt;&gt;</span>
</pre></blockquote>
<p>
while <code>indexed_t::index_type_list</code> holds the types
</p>
<blockquote><pre>
<span class=identifier>multi_index_container</span><span class=special>::</span><span class=identifier>nth_type</span><span class=special>&lt;</span><span class=number>0</span><span class=special>&gt;::</span><span class=identifier>type</span>
<span class=identifier>multi_index_container</span><span class=special>::</span><span class=identifier>nth_type</span><span class=special>&lt;</span><span class=number>1</span><span class=special>&gt;::</span><span class=identifier>type</span>
</pre></blockquote>
<p>
so the typelists are radically different. Check the
<a href="../reference/multi_index_container.html#types">reference</a>
for the exact MPL sequence concepts modeled by these type lists.
</p>
<h3><a name="mpl_synthesis">MPL synthesis</a></h3>
<p>
Although typically indices are specified by means of the
<code>indexed_by</code> construct, actually any MPL sequence of
index specifiers can be provided instead:
</p>
<blockquote><pre>
<span class=keyword>typedef</span> <span class=identifier>mpl</span><span class=special>::</span><span class=identifier>vector</span><span class=special>&lt;</span><span class=identifier>ordered_unique</span><span class=special>&lt;</span><span class=identifier>identity</span><span class=special>&lt;</span><span class=keyword>int</span><span class=special>&gt;</span> <span class=special>&gt;,</span><span class=identifier>sequenced</span><span class=special>&lt;&gt;</span> <span class=special>&gt;</span> <span class=identifier>index_list_t</span><span class=special>;</span>
<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special>&lt;</span>
<span class=keyword>int</span><span class=special>,</span>
<span class=identifier>index_list_t</span>
<span class=special>&gt;</span> <span class=identifier>indexed_t</span><span class=special>;</span>
</pre></blockquote>
<p>
This possibility enables the synthesis of instantiations of
<code>multi_index_container</code> through MPL metaprograms, as the following
example shows:
</p>
<blockquote><pre>
<span class=comment>// original multi_index_container instantiation</span>
<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special>&lt;</span>
<span class=keyword>int</span><span class=special>,</span>
<span class=identifier>indexed_by</span><span class=special>&lt;</span>
<span class=identifier>ordered_unique</span><span class=special>&lt;</span><span class=identifier>identity</span><span class=special>&lt;</span><span class=keyword>int</span><span class=special>&gt;</span> <span class=special>&gt;</span>
<span class=special>&gt;</span>
<span class=special>&gt;</span> <span class=identifier>indexed_t1</span><span class=special>;</span>
<span class=comment>// we take its index list and add an index</span>
<span class=keyword>typedef</span> <span class=identifier>boost</span><span class=special>::</span><span class=identifier>mpl</span><span class=special>::</span><span class=identifier>push_front</span><span class=special>&lt;</span>
<span class=identifier>indexed_t1</span><span class=special>::</span><span class=identifier>index_specifier_type_list</span><span class=special>,</span>
<span class=identifier>sequenced</span><span class=special>&lt;&gt;</span>
<span class=special>&gt;::</span><span class=identifier>type</span> <span class=identifier>index_list_t</span><span class=special>;</span>
<span class=comment>// augmented multi_index_container</span>
<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special>&lt;</span>
<span class=keyword>int</span><span class=special>,</span>
<span class=identifier>index_list_t</span>
<span class=special>&gt;</span> <span class=identifier>indexed_t2</span><span class=special>;</span>
</pre></blockquote>
<hr>
<div class="prev_link"><a href="debug.html"><img src="../prev.gif" alt="debugging support" border="0"><br>
Debugging support
</a></div>
<div class="up_link"><a href="index.html"><img src="../up.gif" alt="Boost.MultiIndex tutorial" border="0"><br>
Boost.MultiIndex tutorial
</a></div>
<div class="next_link"><a href="../reference/index.html"><img src="../next.gif" alt="Boost.MultiIndex reference" border="0"><br>
Boost.MultiIndex reference
</a></div><br clear="all" style="clear: all;">
<br>
<p>Revised November 7th 2008</p>
<p>&copy; Copyright 2003-2008 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz.
Distributed under the Boost Software
License, Version 1.0. (See accompanying file <a href="../../../../LICENSE_1_0.txt">
LICENSE_1_0.txt</a> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">
http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</body>
</html>

BIN
libs/multi_index/doc/up.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 853 B

View File

@@ -0,0 +1,69 @@
# Boost.MultiIndex examples Jamfile
#
# Copyright 2003-2007 Joaqu<71>n M L<>pez Mu<4D>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)
#
# See http://www.boost.org/libs/multi_index for library home page.
exe basic
: basic.cpp
: <include>$(BOOST_ROOT)
;
exe bimap
: bimap.cpp
: <include>$(BOOST_ROOT)
;
exe complex_structs
: complex_structs.cpp
: <include>$(BOOST_ROOT)
;
exe composite_keys
: composite_keys.cpp
: <include>$(BOOST_ROOT)
;
exe fun_key
: fun_key.cpp
: <include>$(BOOST_ROOT)
;
exe hashed
: hashed.cpp
: <include>$(BOOST_ROOT)
;
exe ip_allocator
: ip_allocator.cpp
: <include>$(BOOST_ROOT) <threading>multi
;
exe non_default_ctor
: non_default_ctor.cpp
: <include>$(BOOST_ROOT)
;
exe random_access
: random_access.cpp
: <include>$(BOOST_ROOT)
;
exe rearrange
: rearrange.cpp
: <include>$(BOOST_ROOT)
;
exe sequenced
: sequenced.cpp
: <include>$(BOOST_ROOT)
;
exe serialization
: serialization.cpp
/boost/serialization//boost_serialization
: <include>$(BOOST_ROOT)
;

View File

@@ -0,0 +1,119 @@
/* Boost.MultiIndex basic example.
*
* Copyright 2003-2013 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
#if !defined(NDEBUG)
#define BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING
#define BOOST_MULTI_INDEX_ENABLE_SAFE_MODE
#endif
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <algorithm>
#include <iostream>
#include <iterator>
#include <string>
using boost::multi_index_container;
using namespace boost::multi_index;
/* an employee record holds its ID, name and age */
struct employee
{
int id;
std::string name;
int age;
employee(int id_,std::string name_,int age_):id(id_),name(name_),age(age_){}
friend std::ostream& operator<<(std::ostream& os,const employee& e)
{
os<<e.id<<" "<<e.name<<" "<<e.age<<std::endl;
return os;
}
};
/* tags for accessing the corresponding indices of employee_set */
struct id{};
struct name{};
struct age{};
/* see Compiler specifics: Use of member_offset for info on
* BOOST_MULTI_INDEX_MEMBER
*/
/* Define a multi_index_container of employees with following indices:
* - a unique index sorted by employee::int,
* - a non-unique index sorted by employee::name,
* - a non-unique index sorted by employee::age.
*/
typedef multi_index_container<
employee,
indexed_by<
ordered_unique<
tag<id>, BOOST_MULTI_INDEX_MEMBER(employee,int,id)>,
ordered_non_unique<
tag<name>,BOOST_MULTI_INDEX_MEMBER(employee,std::string,name)>,
ordered_non_unique<
tag<age>, BOOST_MULTI_INDEX_MEMBER(employee,int,age)> >
> employee_set;
template<typename Tag,typename MultiIndexContainer>
void print_out_by(const MultiIndexContainer& s)
{
/* obtain a reference to the index tagged by Tag */
const typename boost::multi_index::index<MultiIndexContainer,Tag>::type& i=
get<Tag>(s);
typedef typename MultiIndexContainer::value_type value_type;
/* dump the elements of the index to cout */
std::copy(i.begin(),i.end(),std::ostream_iterator<value_type>(std::cout));
}
int main()
{
employee_set es;
es.insert(employee(0,"Joe",31));
es.insert(employee(1,"Robert",27));
es.insert(employee(2,"John",40));
/* next insertion will fail, as there is an employee with
* the same ID
*/
es.insert(employee(2,"Aristotle",2387));
es.insert(employee(3,"Albert",20));
es.insert(employee(4,"John",57));
/* list the employees sorted by ID, name and age */
std::cout<<"by ID"<<std::endl;
print_out_by<id>(es);
std::cout<<std::endl;
std::cout<<"by name"<<std::endl;
print_out_by<name>(es);
std::cout<<std::endl;
std::cout<<"by age"<<std::endl;
print_out_by<age>(es);
std::cout<<std::endl;
return 0;
}

View File

@@ -0,0 +1,149 @@
/* Boost.MultiIndex example of a bidirectional map.
*
* Copyright 2003-2009 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
#if !defined(NDEBUG)
#define BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING
#define BOOST_MULTI_INDEX_ENABLE_SAFE_MODE
#endif
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <iostream>
#include <string>
using boost::multi_index_container;
using namespace boost::multi_index;
/* tags for accessing both sides of a bidirectional map */
struct from{};
struct to{};
/* The class template bidirectional_map wraps the specification
* of a bidirectional map based on multi_index_container.
*/
template<typename FromType,typename ToType>
struct bidirectional_map
{
struct value_type
{
value_type(const FromType& first_,const ToType& second_):
first(first_),second(second_)
{}
FromType first;
ToType second;
};
#if defined(BOOST_NO_POINTER_TO_MEMBER_TEMPLATE_PARAMETERS) ||\
defined(BOOST_MSVC)&&(BOOST_MSVC<1300) ||\
defined(BOOST_INTEL_CXX_VERSION)&&defined(_MSC_VER)&&\
(BOOST_INTEL_CXX_VERSION<=700)
/* see Compiler specifics: Use of member_offset for info on member<> and
* member_offset<>
*/
BOOST_STATIC_CONSTANT(unsigned,from_offset=offsetof(value_type,first));
BOOST_STATIC_CONSTANT(unsigned,to_offset =offsetof(value_type,second));
typedef multi_index_container<
value_type,
indexed_by<
ordered_unique<
tag<from>,member_offset<value_type,FromType,from_offset> >,
ordered_unique<
tag<to>, member_offset<value_type,ToType,to_offset> >
>
> type;
#else
/* A bidirectional map can be simulated as a multi_index_container
* of pairs of (FromType,ToType) with two unique indices, one
* for each member of the pair.
*/
typedef multi_index_container<
value_type,
indexed_by<
ordered_unique<
tag<from>,member<value_type,FromType,&value_type::first> >,
ordered_unique<
tag<to>, member<value_type,ToType,&value_type::second> >
>
> type;
#endif
};
/* a dictionary is a bidirectional map from strings to strings */
typedef bidirectional_map<std::string,std::string>::type dictionary;
int main()
{
dictionary d;
/* Fill up our microdictionary. first members Spanish, second members
* English.
*/
d.insert(dictionary::value_type("hola","hello"));
d.insert(dictionary::value_type("adios","goodbye"));
d.insert(dictionary::value_type("rosa","rose"));
d.insert(dictionary::value_type("mesa","table"));
std::cout<<"enter a word"<<std::endl;
std::string word;
std::getline(std::cin,word);
#if defined(BOOST_NO_MEMBER_TEMPLATES) /* use global get<> and family instead */
dictionary::iterator it=get<from>(d).find(word);
if(it!=d.end()){
std::cout<<word<<" is said "<<it->second<<" in English"<<std::endl;
}
else{
nth_index<dictionary,1>::type::iterator it2=get<1>(d).find(word);
if(it2!=get<1>(d).end()){
std::cout<<word<<" is said "<<it2->first<<" in Spanish"<<std::endl;
}
else std::cout<<"No such word in the dictionary"<<std::endl;
}
#else
/* search the queried word on the from index (Spanish) */
dictionary::iterator it=d.get<from>().find(word);
if(it!=d.end()){ /* found */
/* the second part of the element is the equivalent in English */
std::cout<<word<<" is said "<<it->second<<" in English"<<std::endl;
}
else{
/* word not found in Spanish, try our luck in English */
dictionary::index<to>::type::iterator it2=d.get<to>().find(word);
if(it2!=d.get<to>().end()){
std::cout<<word<<" is said "<<it2->first<<" in Spanish"<<std::endl;
}
else std::cout<<"No such word in the dictionary"<<std::endl;
}
#endif
return 0;
}

View File

@@ -0,0 +1,315 @@
/* Boost.MultiIndex example: complex searches and foreign keys.
*
* Copyright 2003-2008 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
#if !defined(NDEBUG)
#define BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING
#define BOOST_MULTI_INDEX_ENABLE_SAFE_MODE
#endif
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/tuple/tuple.hpp>
#include <iostream>
#include <string>
using boost::multi_index_container;
using namespace boost::multi_index;
/* This small utility that cascades two key extractors will be
* used througout the example.
*/
template<class KeyExtractor1,class KeyExtractor2>
struct key_from_key
{
public:
typedef typename KeyExtractor1::result_type result_type;
key_from_key(
const KeyExtractor1& key1_=KeyExtractor1(),
const KeyExtractor2& key2_=KeyExtractor2()):
key1(key1_),key2(key2_)
{}
template<typename Arg>
result_type operator()(Arg& arg)const
{
return key1(key2(arg));
}
private:
KeyExtractor1 key1;
KeyExtractor2 key2;
};
/* tags for accessing several indices defined below */
struct model{};
struct manufacturer{};
struct price{};
/* a manufacturer struct just holds the name of the manufacturer */
struct car_manufacturer
{
std::string name;
car_manufacturer(const std::string& name_):name(name_){}
};
/* car_model holds the model of car, its price and a pointer to the
* manufacturer. The pointer thing eliminates duplication of the same
* data among cars of the same manufacturer.
*/
struct car_model
{
std::string model;
const car_manufacturer* manufacturer;
int price;
car_model(
const std::string& model_,const car_manufacturer* manufacturer_,int price_):
model(model_),manufacturer(manufacturer_),price(price_)
{}
friend std::ostream& operator<<(std::ostream& os,const car_model& c)
{
os<<c.manufacturer->name<<" "<<c.model<<" $"<<c.price<<std::endl;
return os;
}
};
/* see Compiler specifics: Use of member_offset for info on
* BOOST_MULTI_INDEX_MEMBER
*/
/* Car manufacturers are stored in a multi_index_container with one single
* index on the name member. This is functionally equivalent to an std::set,
* though in this latter case we woud have to define a non-default comparison
* predicate (with multi_index_container, member<> does the work for us.)
*/
typedef multi_index_container<
car_manufacturer,
indexed_by<
ordered_unique<
BOOST_MULTI_INDEX_MEMBER(car_manufacturer,std::string,name)
>
>
> car_manufacturer_table;
/* Define a multi_index_container of car_models with following indices:
* - a unique index sorted by car_model::model,
* - a non-unique index sorted by car_model::manufacturer; note the
* non-standard manufacturer_extractor used.
* - a non-unique index sorted by car_model::price.
*/
typedef multi_index_container<
car_model,
indexed_by<
ordered_unique<
tag<model>,BOOST_MULTI_INDEX_MEMBER(car_model,std::string,model)
>,
ordered_non_unique<
tag<manufacturer>,
key_from_key<
BOOST_MULTI_INDEX_MEMBER(car_manufacturer,const std::string,name),
BOOST_MULTI_INDEX_MEMBER(
car_model,const car_manufacturer *,manufacturer)
>
>,
ordered_non_unique<
tag<price>,BOOST_MULTI_INDEX_MEMBER(car_model,int,price)
>
>
> car_table;
/* We call a *view* to a multi_index_container storing pointers instead of
* actual objects. These views are used in the complex search performed
* in the program. Resorting to multi_index of pointers eliminates
* unnecessary copying of objects, and provides us with an opportunity
* to show how BOOST_MULTI_INDEX_MEMBER can be used with pointer
* type elements.
* car_table_price_view indexes (pointers to) car_models by price.
*/
typedef multi_index_container<
const car_model*,
indexed_by<
ordered_non_unique<BOOST_MULTI_INDEX_MEMBER(car_model,const int,price)>
>
> car_table_price_view;
/* car_table_manufacturer_view indexes (pointers to) car_models by
* manufacturer
*/
typedef multi_index_container<
const car_model*,
indexed_by<
ordered_non_unique<
key_from_key<
BOOST_MULTI_INDEX_MEMBER(car_manufacturer,const std::string,name),
BOOST_MULTI_INDEX_MEMBER(
car_model,const car_manufacturer * const,manufacturer)
>
>
>
> car_table_manufacturer_view;
int main()
{
car_manufacturer_table cmt;
/* Fill the car_manufacturer table and keep pointers to the
* elements inserted.
*/
const car_manufacturer * cadillac=
&*(cmt.insert(car_manufacturer("Cadillac")).first);
const car_manufacturer * ford =
&*(cmt.insert(car_manufacturer("Ford")).first);
const car_manufacturer * bmw =
&*(cmt.insert(car_manufacturer("BMW")).first);
const car_manufacturer * audi =
&*(cmt.insert(car_manufacturer("Audi")).first);
car_table ct;
/* Fill the car_model_table. We use the previously initialized
* pointers to the elements of cmt.
*/
ct.insert(car_model("XLR",cadillac,76200));
ct.insert(car_model("SRX",cadillac,38690));
ct.insert(car_model("CTS",cadillac,30695));
ct.insert(car_model("Escalade",cadillac,54770));
ct.insert(car_model("ESV",cadillac,57195));
ct.insert(car_model("EXT",cadillac,52045));
ct.insert(car_model("Deville",cadillac,45195));
ct.insert(car_model("Seville",cadillac,46330));
ct.insert(car_model("ZX2",ford,15355));
ct.insert(car_model("Thunderbird",ford,43995));
ct.insert(car_model("Windstar",ford,35510));
ct.insert(car_model("Focus",ford,19630));
ct.insert(car_model("Taurus",ford,24290));
ct.insert(car_model("Mustang",ford,39900));
ct.insert(car_model("Crown Victoria",ford,30370));
ct.insert(car_model("325i",bmw,27800));
ct.insert(car_model("545i",bmw,54300));
ct.insert(car_model("745i",bmw,68500));
ct.insert(car_model("M3 coupe",bmw,46500));
ct.insert(car_model("Z4 roadster 3.0i",bmw,40250));
ct.insert(car_model("X5 4.4i",bmw,49950));
ct.insert(car_model("A4 1.8T",audi,25940));
ct.insert(car_model("TT Coupe",audi,33940));
ct.insert(car_model("A6 3.0",audi,36640));
ct.insert(car_model("Allroad quattro 2.7T",audi,40640));
ct.insert(car_model("A8 L",audi,69190));
std::cout<<"enter a car manufacturer"<<std::endl;
std::string cm;
std::getline(std::cin,cm);
/* check for manufacturer */
car_manufacturer_table::iterator icm=cmt.find(cm);
if(icm==cmt.end()){
std::cout<<"no such manufacturer in the table"<<std::endl;
return 0;
}
std::cout<<"enter a minimum price"<<std::endl;
int min_price;
std::cin>>min_price;
std::cout<<"enter a maximum price"<<std::endl;
int max_price;
std::cin>>max_price;
{
/* method 1 */
/* find all the cars for the manufacturer given */
boost::multi_index::index<car_table,manufacturer>::type::iterator ic0,ic1;
boost::tuples::tie(ic0,ic1)=get<manufacturer>(ct).equal_range(cm);
/* construct a view (indexed by price) with these */
car_table_price_view ctpv;
while(ic0!=ic1){
ctpv.insert(&*ic0);
++ic0;
}
/* select the cars in the range given */
car_table_price_view::iterator ictpv0=ctpv.lower_bound(min_price);
car_table_price_view::iterator ictpv1=ctpv.upper_bound(max_price);
if(ictpv0==ictpv1){
std::cout<<"no cars in the range given"<<std::endl;
return 0;
}
/* list them */
std::cout<<"listing by method 1"<<std::endl;
while(ictpv0!=ictpv1){
std::cout<<**ictpv0;
++ictpv0;
}
std::cout<<std::endl;
}
{
/* method 2 will give the same results */
/* find the cars in the range given */
boost::multi_index::index<car_table,price>::type::iterator ic0,ic1;
ic0=get<price>(ct).lower_bound(min_price);
ic1=get<price>(ct).upper_bound(max_price);
/* construct a view with these */
car_table_manufacturer_view ctmv;
while(ic0!=ic1){
ctmv.insert(&*ic0);
++ic0;
}
/* select the cars with given manufacturer */
car_table_manufacturer_view::iterator ictmv0,ictmv1;
boost::tuples::tie(ictmv0,ictmv1)=ctmv.equal_range(cm);
if(ictmv0==ictmv1){
std::cout<<"no cars in the range given"<<std::endl;
return 0;
}
/* list them */
std::cout<<"listing by method 2"<<std::endl;
while(ictmv0!=ictmv1){
std::cout<<**ictmv0;
++ictmv0;
}
std::cout<<std::endl;
}
return 0;
}

View File

@@ -0,0 +1,285 @@
/* Boost.MultiIndex example of composite keys.
*
* Copyright 2003-2008 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
#if !defined(NDEBUG)
#define BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING
#define BOOST_MULTI_INDEX_ENABLE_SAFE_MODE
#endif
#include <boost/call_traits.hpp>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/composite_key.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/next_prior.hpp>
#include <boost/tokenizer.hpp>
#include <functional>
#include <iostream>
#include <iterator>
#include <map>
#include <string>
using namespace boost::multi_index;
/* A file record maintains some info on name and size as well
* as a pointer to the directory it belongs (null meaning the root
* directory.)
*/
struct file_entry
{
file_entry(
std::string name_,unsigned size_,bool is_dir_,const file_entry* dir_):
name(name_),size(size_),is_dir(is_dir_),dir(dir_)
{}
std::string name;
unsigned size;
bool is_dir;
const file_entry* dir;
friend std::ostream& operator<<(std::ostream& os,const file_entry& f)
{
os<<f.name<<"\t"<<f.size;
if(f.is_dir)os<<"\t <dir>";
return os;
}
};
/* A file system is just a multi_index_container of entries with indices on
* file and size. These indices are firstly ordered by directory, as commands
* work on a current directory basis. Composite keys are just fine to model
* this.
* NB: The use of derivation here instead of simple typedef is explained in
* Compiler specifics: type hiding.
*/
struct name_key:composite_key<
file_entry,
BOOST_MULTI_INDEX_MEMBER(file_entry,const file_entry*,dir),
BOOST_MULTI_INDEX_MEMBER(file_entry,std::string,name)
>{};
struct size_key:composite_key<
file_entry,
BOOST_MULTI_INDEX_MEMBER(file_entry,const file_entry* const,dir),
BOOST_MULTI_INDEX_MEMBER(file_entry,unsigned,size)
>{};
/* see Compiler specifics: composite_key in compilers without partial
* template specialization, for info on composite_key_result_less
*/
typedef multi_index_container<
file_entry,
indexed_by<
/* primary index sorted by name (inside the same directory) */
ordered_unique<name_key>,
/* secondary index sorted by size (inside the same directory) */
ordered_non_unique<size_key>
>
> file_system;
/* typedef's of the two indices of file_system */
typedef nth_index<file_system,0>::type file_system_by_name;
typedef nth_index<file_system,1>::type file_system_by_size;
/* We build a rudimentary file system simulation out of some global
* info and a map of commands provided to the user.
*/
static file_system fs; /* the one and only file system */
static file_system_by_name& fs_by_name=fs; /* name index to fs */
static file_system_by_size& fs_by_size=get<1>(fs); /* size index to fs */
static const file_entry* current_dir=0; /* root directory */
/* command framework */
/* A command provides an execute memfun fed with the corresponding params
* (first param is stripped off as it serves to identify the command
* currently being used.)
*/
typedef boost::tokenizer<boost::char_separator<char> > command_tokenizer;
class command
{
public:
virtual ~command(){}
virtual void execute(
command_tokenizer::iterator tok1,command_tokenizer::iterator tok2)=0;
};
/* available commands */
/* cd: syntax cd [.|..|<directory>] */
class command_cd:public command
{
public:
virtual void execute(
command_tokenizer::iterator tok1,command_tokenizer::iterator tok2)
{
if(tok1==tok2)return;
std::string dir=*tok1++;
if(dir==".")return;
if(dir==".."){
if(current_dir)current_dir=current_dir->dir;
return;
}
file_system_by_name::iterator it=fs.find(
boost::make_tuple(current_dir,dir));
if(it==fs.end()){
std::cout<<"non-existent directory"<<std::endl;
return;
}
if(!it->is_dir){
std::cout<<dir<<" is not a directory"<<std::endl;
return;
}
current_dir=&*it;
}
};
static command_cd cd;
/* ls: syntax ls [-s] */
class command_ls:public command
{
public:
virtual void execute(
command_tokenizer::iterator tok1,command_tokenizer::iterator tok2)
{
std::string option;
if(tok1!=tok2)option=*tok1++;
if(!option.empty()){
if(option!="-s"){
std::cout<<"incorrect parameter"<<std::endl;
return;
}
/* list by size */
file_system_by_size::iterator it0,it1;
boost::tie(it0,it1)=fs_by_size.equal_range(
boost::make_tuple(current_dir));
std::copy(it0,it1,std::ostream_iterator<file_entry>(std::cout,"\n"));
return;
}
/* list by name */
file_system_by_name::iterator it0,it1;
boost::tie(it0,it1)=fs.equal_range(boost::make_tuple(current_dir));
std::copy(it0,it1,std::ostream_iterator<file_entry>(std::cout,"\n"));
}
};
static command_ls ls;
/* mkdir: syntax mkdir <directory> */
class command_mkdir:public command
{
public:
virtual void execute(
command_tokenizer::iterator tok1,command_tokenizer::iterator tok2)
{
std::string dir;
if(tok1!=tok2)dir=*tok1++;
if(dir.empty()){
std::cout<<"missing parameter"<<std::endl;
return;
}
if(dir=="."||dir==".."){
std::cout<<"incorrect parameter"<<std::endl;
return;
}
if(!fs.insert(file_entry(dir,0,true,current_dir)).second){
std::cout<<"directory already exists"<<std::endl;
return;
}
}
};
static command_mkdir mkdir;
/* table of commands, a map from command names to class command pointers */
typedef std::map<std::string,command*> command_table;
static command_table cmt;
int main()
{
/* fill the file system with some data */
file_system::iterator it0,it1;
fs.insert(file_entry("usr.cfg",240,false,0));
fs.insert(file_entry("memo.txt",2430,false,0));
it0=fs.insert(file_entry("dev",0,true,0)).first;
fs.insert(file_entry("tty0",128,false,&*it0));
fs.insert(file_entry("tty1",128,false,&*it0));
it0=fs.insert(file_entry("usr",0,true,0)).first;
it1=fs.insert(file_entry("bin",0,true,&*it0)).first;
fs.insert(file_entry("bjam",172032,false,&*it1));
it0=fs.insert(file_entry("home",0,true,0)).first;
it1=fs.insert(file_entry("andy",0,true,&*it0)).first;
fs.insert(file_entry("logo.jpg",5345,false,&*it1)).first;
fs.insert(file_entry("foo.cpp",890,false,&*it1)).first;
fs.insert(file_entry("foo.hpp",93,false,&*it1)).first;
fs.insert(file_entry("foo.html",750,false,&*it1)).first;
fs.insert(file_entry("a.obj",12302,false,&*it1)).first;
fs.insert(file_entry(".bash_history",8780,false,&*it1)).first;
it1=fs.insert(file_entry("rachel",0,true,&*it0)).first;
fs.insert(file_entry("test.py",650,false,&*it1)).first;
fs.insert(file_entry("todo.txt",241,false,&*it1)).first;
fs.insert(file_entry(".bash_history",9510,false,&*it1)).first;
/* fill the command table */
cmt["cd"] =&cd;
cmt["ls"] =&ls;
cmt["mkdir"]=&mkdir;
/* main looop */
for(;;){
/* print out the current directory and the prompt symbol */
if(current_dir)std::cout<<current_dir->name;
std::cout<<">";
/* get an input line from the user: if empty, exit the program */
std::string com;
std::getline(std::cin,com);
command_tokenizer tok(com,boost::char_separator<char>(" \t\n"));
if(tok.begin()==tok.end())break; /* null command, exit */
/* select the corresponding command and execute it */
command_table::iterator it=cmt.find(*tok.begin());
if(it==cmt.end()){
std::cout<<"invalid command"<<std::endl;
continue;
}
it->second->execute(boost::next(tok.begin()),tok.end());
}
return 0;
}

View File

@@ -0,0 +1,100 @@
/* Boost.MultiIndex example of functions used as key extractors.
*
* Copyright 2003-2008 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
#if !defined(NDEBUG)
#define BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING
#define BOOST_MULTI_INDEX_ENABLE_SAFE_MODE
#endif
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/global_fun.hpp>
#include <boost/multi_index/mem_fun.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <iostream>
#include <string>
using namespace boost::multi_index;
/* A name record consists of the given name (e.g. "Charlie")
* and the family name (e.g. "Brown"). The full name, calculated
* by name_record::name() is laid out in the "phonebook order"
* family name + given_name.
*/
struct name_record
{
name_record(std::string given_name_,std::string family_name_):
given_name(given_name_),family_name(family_name_)
{}
std::string name()const
{
std::string str=family_name;
str+=" ";
str+=given_name;
return str;
}
private:
std::string given_name;
std::string family_name;
};
std::string::size_type name_record_length(const name_record& r)
{
return r.name().size();
}
/* multi_index_container with indices based on name_record::name()
* and name_record_length().
* See Compiler specifics: Use of const_mem_fun_explicit and
* mem_fun_explicit for info on BOOST_MULTI_INDEX_CONST_MEM_FUN.
*/
typedef multi_index_container<
name_record,
indexed_by<
ordered_unique<
BOOST_MULTI_INDEX_CONST_MEM_FUN(name_record,std::string,name)
>,
ordered_non_unique<
global_fun<const name_record&,std::string::size_type,name_record_length>
>
>
> name_record_set;
int main()
{
name_record_set ns;
ns.insert(name_record("Joe","Smith"));
ns.insert(name_record("Robert","Nightingale"));
ns.insert(name_record("Robert","Brown"));
ns.insert(name_record("Marc","Tuxedo"));
/* list the names in ns in phonebook order */
std::cout<<"Phonenook order\n"
<<"---------------"<<std::endl;
for(name_record_set::iterator it=ns.begin();it!=ns.end();++it){
std::cout<<it->name()<<std::endl;
}
/* list the names in ns according to their length*/
std::cout<<"\nLength order\n"
<< "------------"<<std::endl;
for(nth_index<name_record_set,1>::type::iterator it1=get<1>(ns).begin();
it1!=get<1>(ns).end();++it1){
std::cout<<it1->name()<<std::endl;
}
return 0;
}

View File

@@ -0,0 +1,124 @@
/* Boost.MultiIndex example of use of hashed indices.
*
* Copyright 2003-2008 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
#if !defined(NDEBUG)
#define BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING
#define BOOST_MULTI_INDEX_ENABLE_SAFE_MODE
#endif
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/tokenizer.hpp>
#include <iomanip>
#include <iostream>
#include <string>
using boost::multi_index_container;
using namespace boost::multi_index;
/* word_counter keeps the ocurrences of words inserted. A hashed
* index allows for fast checking of preexisting entries.
*/
struct word_counter_entry
{
std::string word;
unsigned int occurrences;
word_counter_entry(std::string word_):word(word_),occurrences(0){}
};
/* see Compiler specifics: Use of member_offset for info on
* BOOST_MULTI_INDEX_MEMBER
*/
typedef multi_index_container<
word_counter_entry,
indexed_by<
ordered_non_unique<
BOOST_MULTI_INDEX_MEMBER(word_counter_entry,unsigned int,occurrences),
std::greater<unsigned int> /* sorted beginning with most frequent */
>,
hashed_unique<
BOOST_MULTI_INDEX_MEMBER(word_counter_entry,std::string,word)
>
>
> word_counter;
/* utilities */
template<typename T>
struct increment
{
void operator()(T& x)const{++x;}
};
typedef boost::tokenizer<boost::char_separator<char> > text_tokenizer;
int main()
{
/* boostinspect:noascii */
std::string text=
"En un lugar de la Mancha, de cuyo nombre no quiero acordarme, no ha "
"mucho tiempo que viv<69>a un hidalgo de los de lanza en astillero, adarga "
"antigua, roc<6F>n flaco y galgo corredor. Una olla de algo m<>s vaca que "
"carnero, salpic<69>n las m<>s noches, duelos y quebrantos los s<>bados, "
"lantejas los viernes, alg<6C>n palomino de a<>adidura los domingos, "
"consum<EFBFBD>an las tres partes de su hacienda. El resto della conclu<6C>an sayo "
"de velarte, calzas de velludo para las fiestas, con sus pantuflos de lo "
"mesmo, y los d<>as de entresemana se honraba con su vellor<6F> de lo m<>s "
"fino. Ten<65>a en su casa una ama que pasaba de los cuarenta, y una "
"sobrina que no llegaba a los veinte, y un mozo de campo y plaza, que "
"as<EFBFBD> ensillaba el roc<6F>n como tomaba la podadera. Frisaba la edad de "
"nuestro hidalgo con los cincuenta a<>os; era de complexi<78>n recia, seco "
"de carnes, enjuto de rostro, gran madrugador y amigo de la caza. "
"Quieren decir que ten<65>a el sobrenombre de Quijada, o Quesada, que en "
"esto hay alguna diferencia en los autores que deste caso escriben; "
"aunque, por conjeturas veros<6F>miles, se deja entender que se llamaba "
"Quejana. Pero esto importa poco a nuestro cuento; basta que en la "
"narraci<EFBFBD>n d<>l no se salga un punto de la verdad.";
/* feed the text into the container */
word_counter wc;
text_tokenizer tok(text,boost::char_separator<char>(" \t\n.,;:!?'\"-"));
unsigned int total_occurrences=0;
for(text_tokenizer::iterator it=tok.begin(),it_end=tok.end();
it!=it_end;++it){
/* Insert the word into the container. If duplicate, wit will point to
* the preexistent entry.
*/
++total_occurrences;
word_counter::iterator wit=wc.insert(*it).first;
/* Increment occurrences.
* In a lambda-capable compiler, this can be written as:
* wc.modify_key(wit,++_1);
*/
wc.modify_key(wit,increment<unsigned int>());
}
/* list words by frequency of appearance */
std::cout<<std::fixed<<std::setprecision(2);
for(word_counter::iterator wit=wc.begin(),wit_end=wc.end();
wit!=wit_end;++wit){
std::cout<<std::setw(11)<<wit->word<<": "
<<std::setw(5) <<100.0*wit->occurrences/total_occurrences<<"%"
<<std::endl;
}
return 0;
}

View File

@@ -0,0 +1,293 @@
/* Boost.MultiIndex example of use of Boost.Interprocess allocators.
*
* Copyright 2003-2008 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
#if !defined(NDEBUG)
#define BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING
#define BOOST_MULTI_INDEX_ENABLE_SAFE_MODE
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <algorithm>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <boost/interprocess/managed_mapped_file.hpp>
#include <boost/interprocess/sync/named_mutex.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/member.hpp>
#include <iostream>
#include <iterator>
#include <sstream>
#include <string>
using boost::multi_index_container;
using namespace boost::multi_index;
namespace bip=boost::interprocess;
/* shared_string is a string type placeable in shared memory,
* courtesy of Boost.Interprocess.
*/
typedef bip::basic_string<
char,std::char_traits<char>,
bip::allocator<char,bip::managed_mapped_file::segment_manager>
> shared_string;
/* Book record. All its members can be placed in shared memory,
* hence the structure itself can too.
*/
struct book
{
shared_string name;
shared_string author;
unsigned pages;
unsigned prize;
book(const shared_string::allocator_type& al):
name(al),author(al),pages(0),prize(0)
{}
friend std::ostream& operator<<(std::ostream& os,const book& b)
{
os<<b.author<<": \""<<b.name<<"\", $"<<b.prize<<", "<<b.pages<<" pages\n";
return os;
}
};
/* partial_str_less allows for partial searches taking into account
* only the first n chars of the strings compared against. See
* Tutorial: Basics: Special lookup operations for more info on this
* type of comparison functors.
*/
/* partial_string is a mere string holder used to differentiate from
* a plain string.
*/
struct partial_string
{
partial_string(const shared_string& str):str(str){}
shared_string str;
};
struct partial_str_less
{
bool operator()(const shared_string& x,const shared_string& y)const
{
return x<y;
}
bool operator()(const shared_string& x,const partial_string& y)const
{
return x.substr(0,y.str.size())<y.str;
}
bool operator()(const partial_string& x,const shared_string& y)const
{
return x.str<y.substr(0,x.str.size());
}
};
/* Define a multi_index_container of book records with indices on
* author, name and prize. The index on names allows for partial
* searches. This container can be placed in shared memory because:
* * book can be placed in shared memory.
* * We are using a Boost.Interprocess specific allocator.
*/
/* see Compiler specifics: Use of member_offset for info on
* BOOST_MULTI_INDEX_MEMBER
*/
typedef multi_index_container<
book,
indexed_by<
ordered_non_unique<
BOOST_MULTI_INDEX_MEMBER(book,shared_string,author)
>,
ordered_non_unique<
BOOST_MULTI_INDEX_MEMBER(book,shared_string,name),
partial_str_less
>,
ordered_non_unique<
BOOST_MULTI_INDEX_MEMBER(book,unsigned,prize)
>
>,
bip::allocator<book,bip::managed_mapped_file::segment_manager>
> book_container;
/* A small utility to get data entered via std::cin */
template<typename T>
void enter(const char* msg,T& t)
{
std::cout<<msg;
std::string str;
std::getline(std::cin,str);
std::istringstream iss(str);
iss>>t;
}
void enter(const char* msg,std::string& str)
{
std::cout<<msg;
std::getline(std::cin,str);
}
void enter(const char* msg,shared_string& str)
{
std::cout<<msg;
std::string stdstr;
std::getline(std::cin,stdstr);
str=stdstr.c_str();
}
int main()
{
/* Create (or open) the memory mapped file where the book container
* is stored, along with a mutex for synchronized access.
*/
bip::managed_mapped_file seg(
bip::open_or_create,"./book_container.db",
65536);
bip::named_mutex mutex(
bip::open_or_create,"7FD6D7E8-320B-11DC-82CF-F0B655D89593");
/* create or open the book container in shared memory */
book_container* pbc=seg.find_or_construct<book_container>("book container")(
book_container::ctor_args_list(),
book_container::allocator_type(seg.get_segment_manager()));
std::string command_info=
"1. list books by author\n"
"2. list all books by prize\n"
"3. insert a book\n"
"4. delete a book\n"
"0. exit\n";
std::cout<<command_info;
/* main loop */
for(bool exit=false;!exit;){
int command=-1;
enter("command: ",command);
switch(command){
case 0:{ /* exit */
exit=true;
break;
}
case 1:{ /* list books by author */
std::string author;
enter("author (empty=all authors): ",author);
/* operations with the container must be mutex protected */
bip::scoped_lock<bip::named_mutex> lock(mutex);
std::pair<book_container::iterator,book_container::iterator> rng;
if(author.empty()){
rng=std::make_pair(pbc->begin(),pbc->end());
}
else{
rng=pbc->equal_range(
shared_string(
author.c_str(),
shared_string::allocator_type(seg.get_segment_manager())));
}
if(rng.first==rng.second){
std::cout<<"no entries\n";
}
else{
std::copy(
rng.first,rng.second,std::ostream_iterator<book>(std::cout));
}
break;
}
case 2:{ /* list all books by prize */
bip::scoped_lock<bip::named_mutex> lock(mutex);
std::copy(
get<2>(*pbc).begin(),get<2>(*pbc).end(),
std::ostream_iterator<book>(std::cout));
break;
}
case 3:{ /* insert a book */
book b(shared_string::allocator_type(seg.get_segment_manager()));
enter("author: ",b.author);
enter("name: " ,b.name);
enter("prize: " ,b.prize);
enter("pages: " ,b.pages);
std::cout<<"insert the following?\n"<<b<<"(y/n): ";
char yn='n';
enter("",yn);
if(yn=='y'||yn=='Y'){
bip::scoped_lock<bip::named_mutex> lock(mutex);
pbc->insert(b);
}
break;
}
case 4:{ /* delete a book */
shared_string name(
shared_string::allocator_type(seg.get_segment_manager()));
enter(
"name of the book (you can enter\nonly the first few characters): ",
name);
typedef nth_index<book_container,1>::type index_by_name;
index_by_name& idx=get<1>(*pbc);
index_by_name::iterator it;
book b(shared_string::allocator_type(seg.get_segment_manager()));
{
/* Look for a book whose title begins with name. Note that we
* are unlocking after doing the search so as to not leave the
* container blocked during user prompting. That is also why a
* local copy of the book is done.
*/
bip::scoped_lock<bip::named_mutex> lock(mutex);
it=idx.find(partial_string(name));
if(it==idx.end()){
std::cout<<"no such book found\n";
break;
}
b=*it;
}
std::cout<<"delete the following?\n"<<b<<"(y/n): ";
char yn='n';
enter("",yn);
if(yn=='y'||yn=='Y'){
bip::scoped_lock<bip::named_mutex> lock(mutex);
idx.erase(it);
}
break;
}
default:{
std::cout<<"select one option:\n"<<command_info;
break;
}
}
}
return 0;
}

View File

@@ -0,0 +1,96 @@
/* Boost.MultiIndex example of use of multi_index_container::ctor_args_list.
*
* Copyright 2003-2008 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
#if !defined(NDEBUG)
#define BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING
#define BOOST_MULTI_INDEX_ENABLE_SAFE_MODE
#endif
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <algorithm>
#include <iostream>
#include <iterator>
using boost::multi_index_container;
using namespace boost::multi_index;
/* modulo_less order numbers according to their division residual.
* For instance, if modulo==10 then 22 is less than 15 as 22%10==2 and
* 15%10==5.
*/
template<typename IntegralType>
struct modulo_less
{
modulo_less(IntegralType m):modulo(m){}
bool operator()(IntegralType x,IntegralType y)const
{
return (x%modulo)<(y%modulo);
}
private:
IntegralType modulo;
};
/* multi_index_container of unsigned ints holding a "natural" index plus
* an ordering based on modulo_less.
*/
typedef multi_index_container<
unsigned int,
indexed_by<
ordered_unique<identity<unsigned int> >,
ordered_non_unique<identity<unsigned int>, modulo_less<unsigned int> >
>
> modulo_indexed_set;
int main()
{
/* define a modulo_indexed_set with modulo==10 */
modulo_indexed_set::ctor_args_list args_list=
boost::make_tuple(
/* ctor_args for index #0 is default constructible */
nth_index<modulo_indexed_set,0>::type::ctor_args(),
/* first parm is key_from_value, second is our sought for key_compare */
boost::make_tuple(identity<unsigned int>(),modulo_less<unsigned int>(10))
);
modulo_indexed_set m(args_list);
/* this could have be written online without the args_list variable,
* left as it is for explanatory purposes. */
/* insert some numbers */
unsigned int numbers[]={0,1,20,40,33,68,11,101,60,34,88,230,21,4,7,17};
const std::size_t numbers_length(sizeof(numbers)/sizeof(numbers[0]));
m.insert(&numbers[0],&numbers[numbers_length]);
/* lists all numbers in order, along with their "equivalence class", that is,
* the equivalent numbers under modulo_less
*/
for(modulo_indexed_set::iterator it=m.begin();it!=m.end();++it){
std::cout<<*it<<" -> ( ";
nth_index<modulo_indexed_set,1>::type::iterator it0,it1;
boost::tie(it0,it1)=get<1>(m).equal_range(*it);
std::copy(it0,it1,std::ostream_iterator<unsigned int>(std::cout," "));
std::cout<<")"<<std::endl;
}
return 0;
}

View File

@@ -0,0 +1,102 @@
/* Boost.MultiIndex example of use of random access indices.
*
* Copyright 2003-2008 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
#if !defined(NDEBUG)
#define BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING
#define BOOST_MULTI_INDEX_ENABLE_SAFE_MODE
#endif
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/random_access_index.hpp>
#include <boost/tokenizer.hpp>
#include <algorithm>
#include <iostream>
#include <iterator>
#include <string>
using boost::multi_index_container;
using namespace boost::multi_index;
/* text_container holds words as inserted and also keep them indexed
* by dictionary order.
*/
typedef multi_index_container<
std::string,
indexed_by<
random_access<>,
ordered_non_unique<identity<std::string> >
>
> text_container;
/* ordered index */
typedef nth_index<text_container,1>::type ordered_text;
/* Helper function for obtaining the position of an element in the
* container.
*/
template<typename IndexIterator>
text_container::size_type text_position(
const text_container& tc,IndexIterator it)
{
/* project to the base index and calculate offset from begin() */
return project<0>(tc,it)-tc.begin();
}
typedef boost::tokenizer<boost::char_separator<char> > text_tokenizer;
int main()
{
std::string text=
"'Oh, you wicked little thing!' cried Alice, catching up the kitten, "
"and giving it a little kiss to make it understand that it was in "
"disgrace. 'Really, Dinah ought to have taught you better manners! You "
"ought, Dinah, you know you ought!' she added, looking reproachfully at "
"the old cat, and speaking in as cross a voice as she could manage "
"-- and then she scrambled back into the armchair, taking the kitten and "
"the worsted with her, and began winding up the ball again. But she "
"didn't get on very fast, as she was talking all the time, sometimes to "
"the kitten, and sometimes to herself. Kitty sat very demurely on her "
"knee, pretending to watch the progress of the winding, and now and then "
"putting out one paw and gently touching the ball, as if it would be glad "
"to help, if it might.";
/* feed the text into the container */
text_container tc;
tc.reserve(text.size()); /* makes insertion faster */
text_tokenizer tok(text,boost::char_separator<char>(" \t\n.,;:!?'\"-"));
std::copy(tok.begin(),tok.end(),std::back_inserter(tc));
std::cout<<"enter a position (0-"<<tc.size()-1<<"):";
text_container::size_type pos=tc.size();
std::cin>>pos;
if(pos>=tc.size()){
std::cout<<"out of bounds"<<std::endl;
}
else{
std::cout<<"the word \""<<tc[pos]<<"\" appears at position(s): ";
std::pair<ordered_text::iterator,ordered_text::iterator> p=
get<1>(tc).equal_range(tc[pos]);
while(p.first!=p.second){
std::cout<<text_position(tc,p.first++)<<" ";
}
std::cout<<std::endl;
}
return 0;
}

View File

@@ -0,0 +1,265 @@
/* Boost.MultiIndex example of use of rearrange facilities.
*
* Copyright 2003-2015 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
#if !defined(NDEBUG)
#define BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING
#define BOOST_MULTI_INDEX_ENABLE_SAFE_MODE
#endif
#include <boost/config.hpp>
#include <boost/detail/iterator.hpp>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/random_access_index.hpp>
#include <boost/random/binomial_distribution.hpp>
#include <boost/random/uniform_real.hpp>
#include <boost/random/mersenne_twister.hpp>
#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>
#if !defined(BOOST_NO_CXX11_HDR_RANDOM)
#include <random>
#endif
using boost::multi_index_container;
using namespace boost::multi_index;
/* We model a card deck with a random access array containing
* card numbers (from 0 to 51), supplemented with an additional
* index which retains the start ordering.
*/
class deck
{
BOOST_STATIC_CONSTANT(std::size_t,num_cards=52);
typedef multi_index_container<
int,
indexed_by<
random_access<>, /* base index */
random_access<> /* "start" index */
>
> container_type;
container_type cont;
public:
deck()
{
cont.reserve(num_cards);
get<1>(cont).reserve(num_cards);
for(std::size_t i=0;i<num_cards;++i)cont.push_back(i);
}
typedef container_type::iterator iterator;
typedef container_type::size_type size_type;
iterator begin()const{return cont.begin();}
iterator end()const{return cont.end();}
size_type size()const{return cont.size();}
template<typename InputIterator>
void rearrange(InputIterator it)
{
cont.rearrange(it);
}
void reset()
{
/* simply rearrange the base index like the start index */
cont.rearrange(get<1>(cont).begin());
}
std::size_t position(int i)const
{
/* The position of a card in the deck is calculated by locating
* the card through the start index (which is ordered), projecting
* to the base index and diffing with the begin position.
* Resulting complexity: constant.
*/
return project<0>(cont,get<1>(cont).begin()+i)-cont.begin();
}
std::size_t rising_sequences()const
{
/* Iterate through all cards and increment the sequence count
* when the current position is left to the previous.
* Resulting complexity: O(n), n=num_cards.
*/
std::size_t s=1;
std::size_t last_pos=0;
for(std::size_t i=0;i<num_cards;++i){
std::size_t pos=position(i);
if(pos<last_pos)++s;
last_pos=pos;
}
return s;
}
};
/* A vector of reference_wrappers to deck elements can be used
* as a view to the deck container.
* We use a special implicit_reference_wrapper having implicit
* ctor from its base type, as this simplifies the use of generic
* techniques on the resulting data structures.
*/
template<typename T>
class implicit_reference_wrapper:public boost::reference_wrapper<T>
{
private:
typedef boost::reference_wrapper<T> super;
public:
implicit_reference_wrapper(T& t):super(t){}
};
typedef std::vector<implicit_reference_wrapper<const int> > deck_view;
/* Riffle shuffle is modeled like this: A cut is selected in the deck
* following a binomial distribution. Then, cards are randomly selected
* from one packet or the other with probability proportional to
* packet size.
*/
template<typename RandomAccessIterator,typename OutputIterator>
void riffle_shuffle(
RandomAccessIterator first,RandomAccessIterator last,
OutputIterator out)
{
static boost::mt19937 rnd_gen;
typedef typename boost::detail::iterator_traits<
RandomAccessIterator>::difference_type difference_type;
typedef boost::binomial_distribution<
difference_type> rnd_cut_select_type;
typedef boost::uniform_real<> rnd_deck_select_type;
rnd_cut_select_type cut_select(last-first);
RandomAccessIterator middle=first+cut_select(rnd_gen);
difference_type s0=middle-first;
difference_type s1=last-middle;
rnd_deck_select_type deck_select;
while(s0!=0&&s1!=0){
if(deck_select(rnd_gen)<(double)s0/(s0+s1)){
*out++=*first++;
--s0;
}
else{
*out++=*middle++;
--s1;
}
}
std::copy(first,first+s0,out);
std::copy(middle,middle+s1,out);
}
struct riffle_shuffler
{
void operator()(deck& d)const
{
dv.clear();
dv.reserve(d.size());
riffle_shuffle(
d.begin(),d.end(),std::back_inserter(dv)); /* do the shuffling */
d.rearrange(dv.begin()); /* apply to the deck */
}
private:
mutable deck_view dv;
};
/* A truly random shuffle (up to stdlib implementation quality) using
* std::shuffle.
*/
struct random_shuffler
{
void operator()(deck& d)
{
dv.clear();
dv.reserve(d.size());
std::copy(d.begin(),d.end(),std::back_inserter(dv));
shuffle_view();
d.rearrange(dv.begin()); /* apply to the deck */
}
private:
deck_view dv;
#if !defined(BOOST_NO_CXX11_HDR_RANDOM)
std::mt19937 e;
void shuffle_view()
{
std::shuffle(dv.begin(),dv.end(),e);
}
#else
/* for pre-C++11 compilers we use std::random_shuffle */
void shuffle_view()
{
std::random_shuffle(dv.begin(),dv.end());
}
#endif
};
/* Repeat a given shuffling algorithm repeats_num times
* and obtain the resulting rising sequences number. Average
* for tests_num trials.
*/
template<typename Shuffler>
double shuffle_test(
unsigned int repeats_num,unsigned int tests_num
BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE(Shuffler))
{
deck d;
Shuffler sh;
unsigned long total=0;
for(unsigned int n=0;n<tests_num;++n){
for(unsigned m=0;m<repeats_num;++m)sh(d);
total+=d.rising_sequences();
d.reset();
}
return (double)total/tests_num;
}
int main()
{
unsigned rifs_num=0;
unsigned tests_num=0;
std::cout<<"number of riffle shuffles (vg 5):";
std::cin>>rifs_num;
std::cout<<"number of tests (vg 1000):";
std::cin>>tests_num;
std::cout<<"shuffling..."<<std::endl;
std::cout<<"riffle shuffling\n"
" avg number of rising sequences: "
<<shuffle_test<riffle_shuffler>(rifs_num,tests_num)
<<std::endl;
std::cout<<"random shuffling\n"
" avg number of rising sequences: "
<<shuffle_test<random_shuffler>(1,tests_num)
<<std::endl;
return 0;
}

View File

@@ -0,0 +1,100 @@
/* Boost.MultiIndex example of use of sequenced indices.
*
* Copyright 2003-2008 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
#if !defined(NDEBUG)
#define BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING
#define BOOST_MULTI_INDEX_ENABLE_SAFE_MODE
#endif
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/tokenizer.hpp>
#include <algorithm>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <string>
using boost::multi_index_container;
using namespace boost::multi_index;
/* text_container holds words as inserted and also keep them indexed
* by dictionary order.
*/
typedef multi_index_container<
std::string,
indexed_by<
sequenced<>,
ordered_non_unique<identity<std::string> >
>
> text_container;
/* ordered index */
typedef nth_index<text_container,1>::type ordered_text;
typedef boost::tokenizer<boost::char_separator<char> > text_tokenizer;
int main()
{
std::string text=
"Alice was beginning to get very tired of sitting by her sister on the "
"bank, and of having nothing to do: once or twice she had peeped into the "
"book her sister was reading, but it had no pictures or conversations in "
"it, 'and what is the use of a book,' thought Alice 'without pictures or "
"conversation?'";
/* feed the text into the container */
text_container tc;
text_tokenizer tok(text,boost::char_separator<char>(" \t\n.,;:!?'\"-"));
std::copy(tok.begin(),tok.end(),std::back_inserter(tc));
/* list all words in alphabetical order along with their number
* of occurrences
*/
ordered_text& ot=get<1>(tc);
for(ordered_text::iterator it=ot.begin();it!=ot.end();){
std::cout<<std::left<<std::setw(14)<<*it<<":"; /* print the word */
ordered_text::iterator it2=ot.upper_bound(*it); /* jump to next */
std::cout<<std::right<<std::setw(3) /* and compute the distance */
<<std::distance(it,it2)<<" times"<<std::endl;
it=it2;
}
/* reverse the text and print it out */
tc.reverse();
std::cout<<std::endl;
std::copy(
tc.begin(),tc.end(),std::ostream_iterator<std::string>(std::cout," "));
std::cout<<std::endl;
tc.reverse(); /* undo */
/* delete most common English words and print the result */
std::string common_words[]=
{"the","of","and","a","to","in","is","you","that","it",
"he","for","was","on","are","as","with","his","they","at"};
for(std::size_t n=0;n<sizeof(common_words)/sizeof(common_words[0]);++n){
ot.erase(common_words[n]);
}
std::cout<<std::endl;
std::copy(
tc.begin(),tc.end(),std::ostream_iterator<std::string>(std::cout," "));
std::cout<<std::endl;
return 0;
}

View File

@@ -0,0 +1,144 @@
/* Boost.MultiIndex example of serialization of a MRU list.
*
* Copyright 2003-2008 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
#if !defined(NDEBUG)
#define BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING
#define BOOST_MULTI_INDEX_ENABLE_SAFE_MODE
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <algorithm>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <fstream>
#include <iostream>
#include <iterator>
#include <sstream>
#include <string>
using namespace boost::multi_index;
/* An MRU (most recently used) list keeps record of the last n
* inserted items, listing first the newer ones. Care has to be
* taken when a duplicate item is inserted: instead of letting it
* appear twice, the MRU list relocates it to the first position.
*/
template <typename Item>
class mru_list
{
typedef multi_index_container<
Item,
indexed_by<
sequenced<>,
hashed_unique<identity<Item> >
>
> item_list;
public:
typedef Item item_type;
typedef typename item_list::iterator iterator;
mru_list(std::size_t max_num_items_):max_num_items(max_num_items_){}
void insert(const item_type& item)
{
std::pair<iterator,bool> p=il.push_front(item);
if(!p.second){ /* duplicate item */
il.relocate(il.begin(),p.first); /* put in front */
}
else if(il.size()>max_num_items){ /* keep the length <= max_num_items */
il.pop_back();
}
}
iterator begin(){return il.begin();}
iterator end(){return il.end();}
/* Utilities to save and load the MRU list, internally
* based on Boost.Serialization.
*/
void save_to_file(const char* file_name)const
{
std::ofstream ofs(file_name);
boost::archive::text_oarchive oa(ofs);
oa<<boost::serialization::make_nvp("mru",*this);
}
void load_from_file(const char* file_name)
{
std::ifstream ifs(file_name);
if(ifs){
boost::archive::text_iarchive ia(ifs);
ia>>boost::serialization::make_nvp("mru",*this);
}
}
private:
item_list il;
std::size_t max_num_items;
/* serialization support */
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive& ar,const unsigned int)
{
ar&BOOST_SERIALIZATION_NVP(il);
ar&BOOST_SERIALIZATION_NVP(max_num_items);
}
};
int main()
{
const char* mru_store="mru_store";
/* Construct a MRU limited to 10 items and retrieve its
* previous contents.
*/
mru_list<std::string> mru(10);
mru.load_from_file(mru_store);
/* main loop */
for(;;){
std::cout<<"enter a term: ";
std::string line;
std::getline(std::cin,line);
if(line.empty())break;
std::string term;
std::istringstream iss(line);
iss>>term;
if(term.empty())break;
mru.insert(term);
std::cout<<"most recently entered terms:"<<std::endl;
std::copy(
mru.begin(),mru.end(),
std::ostream_iterator<std::string>(std::cout,"\n"));
}
/* persist the MRU list */
mru.save_to_file(mru_store);
return 0;
}

View File

@@ -0,0 +1,20 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0.1 Transitional//EN">
<!--
Copyright 2003-2004 Joaqu<71>n M L<>pez Mu<4D>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)
-->
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<meta http-equiv="refresh" content="0; URL=doc/index.html">
<title>Boost.MultiIndex Documentation</title>
<link rel="stylesheet" href="doc/style.css" type="text/css">
</head>
<body>
Automatic redirection failed, please go to
<a href="doc/index.html">doc/index.html</a>
</body>
</html>

View File

@@ -0,0 +1,15 @@
{
"key": "multi_index",
"name": "Multi-Index",
"authors": [
"Joaqu\u00edn M L\u00f3pez Mu\u00f1oz"
],
"description": "The Boost Multi-index Containers Library provides a class template named multi_index_container which enables the construction of containers maintaining one or more indices with different sorting and access semantics.",
"category": [
"Containers",
"Data"
],
"maintainers": [
"Joaquin M Lopez Munoz <joaquin.lopezmunoz -at- gmail.com>"
]
}

View File

@@ -0,0 +1,14 @@
# Boost.MultiIndex performance tests Jamfile
#
# Copyright 2003-2006 Joaqu<71>n M L<>pez Mu<4D>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)
#
# See http://www.boost.org/libs/multi_index for library home page.
exe test_perf
: test_perf.cpp
: <include>$(BOOST_ROOT)
: release
;

View File

@@ -0,0 +1,545 @@
/* Boost.MultiIndex performance test.
*
* Copyright 2003-2013 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <algorithm>
#include <assert.h>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/next_prior.hpp>
#include <climits>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <list>
#include <set>
#include <string>
#include <vector>
using namespace std;
using namespace boost::multi_index;
/* Measurement harness by Andrew Koenig, extracted from companion code to
* Stroustrup, B.: "Wrapping C++ Member Function Calls", The C++ Report,
* June 2000, Vol 12/No 6.
* Original code retrievable at: http://www.research.att.com/~bs/wrap_code.cpp
*/
// How many clock units does it take to interrogate the clock?
static double clock_overhead()
{
clock_t k = clock(), start, limit;
// Wait for the clock to tick
do start = clock();
while (start == k);
// interrogate the clock until it has advanced at least a second
// (for reasonable accuracy)
limit = start + CLOCKS_PER_SEC;
unsigned long r = 0;
while ((k = clock()) < limit)
++r;
return double(k - start) / r;
}
// We'd like the odds to be factor:1 that the result is
// within percent% of the median
const int factor = 10;
const int percent = 20;
// Measure a function (object) factor*2 times,
// appending the measurements to the second argument
template<class F>
void measure_aux(F f, vector<double>& mv)
{
static double ovhd = clock_overhead();
// Ensure we don't reallocate in mid-measurement
mv.reserve(mv.size() + factor*2);
// Wait for the clock to tick
clock_t k = clock();
clock_t start;
do start = clock();
while (start == k);
// Do 2*factor measurements
for (int i = 2*factor; i; --i) {
unsigned long count = 0, limit = 1, tcount = 0;
// Original code used CLOCKS_PER_SEC/100
const clock_t clocklimit = start + CLOCKS_PER_SEC/10;
clock_t t;
do {
while (count < limit) {
f();
++count;
}
limit *= 2;
++tcount;
} while ((t = clock()) < clocklimit);
// Wait for the clock to tick again;
clock_t t2;
do ++tcount;
while ((t2 = clock()) == t);
// Append the measurement to the vector
mv.push_back(((t2 - start) - (tcount * ovhd)) / count);
// Establish a new starting point
start = t2;
}
}
// Returns the number of clock units per iteration
// With odds of factor:1, the measurement is within percent% of
// the value returned, which is also the median of all measurements.
template<class F>
double measure(F f)
{
vector<double> mv;
int n = 0; // iteration counter
do {
++n;
// Try 2*factor measurements
measure_aux(f, mv);
assert(mv.size() == 2*n*factor);
// Compute the median. We know the size is even, so we cheat.
sort(mv.begin(), mv.end());
double median = (mv[n*factor] + mv[n*factor-1])/2;
// If the extrema are within threshold of the median, we're done
if (mv[n] > (median * (100-percent))/100 &&
mv[mv.size() - n - 1] < (median * (100+percent))/100)
return median;
} while (mv.size() < factor * 200);
// Give up!
clog << "Help!\n\n";
exit(1);
}
/* dereferencing compare predicate */
template <typename Iterator,typename Compare>
struct it_compare
{
bool operator()(const Iterator& x,const Iterator& y)const{return comp(*x,*y);}
private:
Compare comp;
};
/* list_wrapper and multiset_wrapper adapt std::lists and std::multisets
* to make them conform to a set-like insert interface which test
* routines do assume.
*/
template <typename List>
struct list_wrapper:List
{
typedef typename List::value_type value_type;
typedef typename List::iterator iterator;
pair<iterator,bool> insert(const value_type& v)
{
List::push_back(v);
return pair<iterator,bool>(boost::prior(List::end()),true);
}
};
template <typename Multiset>
struct multiset_wrapper:Multiset
{
typedef typename Multiset::value_type value_type;
typedef typename Multiset::iterator iterator;
pair<iterator,bool> insert(const value_type& v)
{
return pair<iterator,bool>(Multiset::insert(v),true);
}
};
/* space comsumption of manual simulations is determined by checking
* the node sizes of the containers involved. This cannot be done in a
* portable manner, so node_size has to be written on a per stdlibrary
* basis. Add your own versions if necessary.
*/
#if defined(BOOST_DINKUMWARE_STDLIB)
template<typename Container>
size_t node_size(const Container&)
{
return sizeof(*Container().begin()._Mynode());
}
#elif defined(__GLIBCPP__) || defined(__GLIBCXX__)
template<typename Container>
size_t node_size(const Container&)
{
typedef typename Container::iterator::_Link_type node_ptr;
node_ptr p=0;
return sizeof(*p);
}
template<typename Value,typename Allocator>
size_t node_size(const list<Value,Allocator>&)
{
return sizeof(typename list<Value,Allocator>::iterator::_Node);
}
template<typename List>
size_t node_size(const list_wrapper<List>&)
{
return sizeof(typename List::iterator::_Node);
}
#else
/* default version returns 0 by convention */
template<typename Container>
size_t node_size(const Container&)
{
return 0;
}
#endif
/* mono_container runs the tested routine on multi_index and manual
* simulations comprised of one standard container.
* bi_container and tri_container run the equivalent routine for manual
* compositions of two and three standard containers, respectively.
*/
template <typename Container>
struct mono_container
{
mono_container(int n_):n(n_){}
void operator()()
{
typedef typename Container::iterator iterator;
Container c;
for(int i=0;i<n;++i)c.insert(i);
for(iterator it=c.begin();it!=c.end();)c.erase(it++);
}
static size_t multi_index_node_size()
{
return sizeof(*Container().begin().get_node());
}
static size_t node_size()
{
return ::node_size(Container());
}
private:
int n;
};
template <typename Container1,typename Container2>
struct bi_container
{
bi_container(int n_):n(n_){}
void operator()()
{
typedef typename Container1::iterator iterator1;
typedef typename Container2::iterator iterator2;
Container1 c1;
Container2 c2;
for(int i=0;i<n;++i){
iterator1 it1=c1.insert(i).first;
c2.insert(it1);
}
for(iterator2 it2=c2.begin();it2!=c2.end();)
{
c1.erase(*it2);
c2.erase(it2++);
}
}
static size_t node_size()
{
return ::node_size(Container1())+::node_size(Container2());
}
private:
int n;
};
template <typename Container1,typename Container2,typename Container3>
struct tri_container
{
tri_container(int n_):n(n_){}
void operator()()
{
typedef typename Container1::iterator iterator1;
typedef typename Container2::iterator iterator2;
typedef typename Container3::iterator iterator3;
Container1 c1;
Container2 c2;
Container3 c3;
for(int i=0;i<n;++i){
iterator1 it1=c1.insert(i).first;
iterator2 it2=c2.insert(it1).first;
c3.insert(it2);
}
for(iterator3 it3=c3.begin();it3!=c3.end();)
{
c1.erase(**it3);
c2.erase(*it3);
c3.erase(it3++);
}
}
static size_t node_size()
{
return ::node_size(Container1())+
::node_size(Container2())+::node_size(Container3());
}
private:
int n;
};
/* measure and compare two routines for several numbers of elements
* and also estimates relative memory consumption.
*/
template <typename IndexedTest,typename ManualTest>
void run_tests(const char* title)
{
cout<<fixed<<setprecision(2);
cout<<title<<endl;
int n=1000;
for(int i=0;i<3;++i){
double indexed_t=measure(IndexedTest(n));
double manual_t=measure(ManualTest(n));
cout<<" 10^"<<i+3<<" elmts: "
<<setw(6)<<100.0*indexed_t/manual_t<<"% "
<<"("
<<setw(6)<<1000.0*indexed_t/CLOCKS_PER_SEC<<" ms / "
<<setw(6)<<1000.0*manual_t/CLOCKS_PER_SEC<<" ms)"
<<endl;
n*=10;
}
size_t indexed_t_node_size=IndexedTest::multi_index_node_size();
size_t manual_t_node_size=ManualTest::node_size();
if(manual_t_node_size){
cout<<" space gain: "
<<setw(6)<<100.0*indexed_t_node_size/manual_t_node_size<<"%"<<endl;
}
}
/* compare_structures accept a multi_index_container instantiation and
* several standard containers, builds a manual simulation out of the
* latter and run the tests.
*/
template <typename IndexedType,typename ManualType>
void compare_structures(const char* title)
{
run_tests<
mono_container<IndexedType>,
mono_container<ManualType>
>(title);
}
template <typename IndexedType,typename ManualType1,typename ManualType2>
void compare_structures2(const char* title)
{
run_tests<
mono_container<IndexedType>,
bi_container<ManualType1,ManualType2>
>(title);
}
template <
typename IndexedType,
typename ManualType1,typename ManualType2,typename ManualType3
>
void compare_structures3(const char* title)
{
run_tests<
mono_container<IndexedType>,
tri_container<ManualType1,ManualType2,ManualType3>
>(title);
}
int main()
{
/* some stdlibs provide the discussed but finally rejected std::identity */
using boost::multi_index::identity;
{
/* 1 ordered index */
typedef multi_index_container<int> indexed_t;
typedef set<int> manual_t;
compare_structures<indexed_t,manual_t>(
"1 ordered index");
}
{
/* 1 sequenced index */
typedef list_wrapper<
multi_index_container<
int,
indexed_by<sequenced<> >
>
> indexed_t;
typedef list_wrapper<list<int> > manual_t;
compare_structures<indexed_t,manual_t>(
"1 sequenced index");
}
{
/* 2 ordered indices */
typedef multi_index_container<
int,
indexed_by<
ordered_unique<identity<int> >,
ordered_non_unique<identity<int> >
>
> indexed_t;
typedef set<int> manual_t1;
typedef multiset<
manual_t1::iterator,
it_compare<
manual_t1::iterator,
manual_t1::key_compare
>
> manual_t2;
compare_structures2<indexed_t,manual_t1,manual_t2>(
"2 ordered indices");
}
{
/* 1 ordered index + 1 sequenced index */
typedef multi_index_container<
int,
indexed_by<
boost::multi_index::ordered_unique<identity<int> >,
sequenced<>
>
> indexed_t;
typedef list_wrapper<
list<int>
> manual_t1;
typedef multiset<
manual_t1::iterator,
it_compare<
manual_t1::iterator,
std::less<int>
>
> manual_t2;
compare_structures2<indexed_t,manual_t1,manual_t2>(
"1 ordered index + 1 sequenced index");
}
{
/* 3 ordered indices */
typedef multi_index_container<
int,
indexed_by<
ordered_unique<identity<int> >,
ordered_non_unique<identity<int> >,
ordered_non_unique<identity<int> >
>
> indexed_t;
typedef set<int> manual_t1;
typedef multiset_wrapper<
multiset<
manual_t1::iterator,
it_compare<
manual_t1::iterator,
manual_t1::key_compare
>
>
> manual_t2;
typedef multiset<
manual_t2::iterator,
it_compare<
manual_t2::iterator,
manual_t2::key_compare
>
> manual_t3;
compare_structures3<indexed_t,manual_t1,manual_t2,manual_t3>(
"3 ordered indices");
}
{
/* 2 ordered indices + 1 sequenced index */
typedef multi_index_container<
int,
indexed_by<
ordered_unique<identity<int> >,
ordered_non_unique<identity<int> >,
sequenced<>
>
> indexed_t;
typedef list_wrapper<
list<int>
> manual_t1;
typedef multiset_wrapper<
multiset<
manual_t1::iterator,
it_compare<
manual_t1::iterator,
std::less<int>
>
>
> manual_t2;
typedef multiset<
manual_t2::iterator,
it_compare<
manual_t2::iterator,
manual_t2::key_compare
>
> manual_t3;
compare_structures3<indexed_t,manual_t1,manual_t2,manual_t3>(
"2 ordered indices + 1 sequenced index");
}
return 0;
}

View File

@@ -0,0 +1,58 @@
# Boost.MultiIndex tests Jamfile
#
# Copyright 2003-2015 Joaqu<71>n M L<>pez Mu<4D>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)
#
# See http://www.boost.org/libs/multi_index for library home page.
import os ;
import type ;
# Windows Vista UAC has an heuristic by which executable files whose name
# contains any of the words "install", "setup", "update", etc. are assumed
# to be installation packages needing administrative rights, which causes
# the system to bring up a window asking for execution confirmation by the
# user, thus interferring in the unattended bjam process.
# Problem bypassed by changing the EXE names containing a taboo word.
# Thanks to Rene Rivera for guidance on the use of the <tag> feature.
rule change-test_update-exe-name ( name : type ? : property-set )
{
if [ os.on-windows ] && [ type.is-subtype $(type) EXE ]
{
return test_updat.exe ;
}
}
test-suite "multi_index" :
[ run test_basic.cpp test_basic_main.cpp ]
[ run test_capacity.cpp test_capacity_main.cpp ]
[ run test_comparison.cpp test_comparison_main.cpp ]
[ run test_composite_key.cpp test_composite_key_main.cpp ]
[ run test_conv_iterators.cpp test_conv_iterators_main.cpp ]
[ run test_copy_assignment.cpp test_copy_assignment_main.cpp ]
[ run test_hash_ops.cpp test_hash_ops_main.cpp ]
[ run test_iterators.cpp test_iterators_main.cpp ]
[ run test_key_extractors.cpp test_key_extractors_main.cpp ]
[ run test_list_ops.cpp test_list_ops_main.cpp ]
[ run test_modifiers.cpp test_modifiers_main.cpp ]
[ run test_mpl_ops.cpp test_mpl_ops_main.cpp ]
[ run test_observers.cpp test_observers_main.cpp ]
[ run test_projection.cpp test_projection_main.cpp ]
[ run test_range.cpp test_range_main.cpp ]
[ run test_rank_ops.cpp test_rank_ops_main.cpp ]
[ run test_rearrange.cpp test_rearrange_main.cpp ]
[ run test_safe_mode.cpp test_safe_mode_main.cpp ]
[ run test_serialization.cpp test_serialization1.cpp
test_serialization2.cpp test_serialization3.cpp
test_serialization_main.cpp
/boost/serialization//boost_serialization ]
[ run test_set_ops.cpp test_set_ops_main.cpp ]
[ run test_special_set_ops.cpp test_special_set_ops_main.cpp ]
[ run test_update.cpp test_update_main.cpp
: : :
-<tag>@$(BOOST_JAMROOT_MODULE)%$(BOOST_JAMROOT_MODULE).tag
<tag>@change-test_update-exe-name ]
;

View File

@@ -0,0 +1,153 @@
/* Used in Boost.MultiIndex tests.
*
* Copyright 2003-2015 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_TEST_EMPLOYEE_HPP
#define BOOST_MULTI_INDEX_TEST_EMPLOYEE_HPP
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <boost/move/core.hpp>
#include <boost/move/utility.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/random_access_index.hpp>
#include <boost/multi_index/ranked_index.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <cstddef>
#include <ostream>
#include <string>
#include "non_std_allocator.hpp"
struct employee
{
int id;
std::string name;
int age;
int ssn;
employee(int id_,std::string name_,int age_,int ssn_):
id(id_),name(name_),age(age_),ssn(ssn_)
{}
employee(const employee& x):
id(x.id),name(x.name),age(x.age),ssn(x.ssn)
{}
employee(BOOST_RV_REF(employee) x):
id(x.id),name(boost::move(x.name)),age(x.age),ssn(x.ssn)
{}
employee& operator=(BOOST_COPY_ASSIGN_REF(employee) x)
{
id=x.id;
name=x.name;
age=x.age;
ssn=x.ssn;
return *this;
};
employee& operator=(BOOST_RV_REF(employee) x)
{
id=x.id;
name=boost::move(x.name);
age=x.age;
ssn=x.ssn;
return *this;
}
bool operator==(const employee& x)const
{
return id==x.id&&name==x.name&&age==x.age;
}
bool operator<(const employee& x)const
{
return id<x.id;
}
bool operator!=(const employee& x)const{return !(*this==x);}
bool operator> (const employee& x)const{return x<*this;}
bool operator>=(const employee& x)const{return !(*this<x);}
bool operator<=(const employee& x)const{return !(x<*this);}
struct comp_id
{
bool operator()(int x,const employee& e2)const{return x<e2.id;}
bool operator()(const employee& e1,int x)const{return e1.id<x;}
};
friend std::ostream& operator<<(std::ostream& os,const employee& e)
{
os<<e.id<<" "<<e.name<<" "<<e.age<<std::endl;
return os;
}
private:
BOOST_COPYABLE_AND_MOVABLE(employee)
};
struct name{};
struct by_name{};
struct age{};
struct as_inserted{};
struct ssn{};
struct randomly{};
struct employee_set_indices:
boost::mpl::vector<
boost::multi_index::ordered_unique<
boost::multi_index::identity<employee> >,
boost::multi_index::hashed_non_unique<
boost::multi_index::tag<name,by_name>,
BOOST_MULTI_INDEX_MEMBER(employee,std::string,name)>,
boost::multi_index::ranked_non_unique<
boost::multi_index::tag<age>,
BOOST_MULTI_INDEX_MEMBER(employee,int,age)>,
boost::multi_index::sequenced<
boost::multi_index::tag<as_inserted> >,
boost::multi_index::hashed_unique<
boost::multi_index::tag<ssn>,
BOOST_MULTI_INDEX_MEMBER(employee,int,ssn)>,
boost::multi_index::random_access<
boost::multi_index::tag<randomly> > >
{};
typedef
boost::multi_index::multi_index_container<
employee,
employee_set_indices,
non_std_allocator<employee> > employee_set;
#if defined(BOOST_NO_MEMBER_TEMPLATES)
typedef boost::multi_index::nth_index<
employee_set,1>::type employee_set_by_name;
#else
typedef employee_set::nth_index<1>::type employee_set_by_name;
#endif
typedef boost::multi_index::index<
employee_set,age>::type employee_set_by_age;
typedef boost::multi_index::index<
employee_set,as_inserted>::type employee_set_as_inserted;
typedef boost::multi_index::index<
employee_set,ssn>::type employee_set_by_ssn;
#if defined(BOOST_NO_MEMBER_TEMPLATES)
typedef boost::multi_index::index<
employee_set,randomly>::type employee_set_randomly;
#else
typedef employee_set::index<
randomly>::type employee_set_randomly;
#endif
#endif

View File

@@ -0,0 +1,137 @@
/* Used in Boost.MultiIndex tests.
*
* Copyright 2003-2015 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_TEST_NON_STD_ALLOCATOR_HPP
#define BOOST_MULTI_INDEX_TEST_NON_STD_ALLOCATOR_HPP
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <boost/throw_exception.hpp>
#include <iterator>
#include <cstddef>
template<typename T>
class non_raw_pointer
{
public:
typedef std::ptrdiff_t difference_type;
typedef T value_type;
typedef T* pointer;
typedef T& reference;
typedef std::random_access_iterator_tag iterator_category;
non_raw_pointer(){}
explicit non_raw_pointer(T* p_):p(p_){}
T& operator*()const
{
#if !defined(BOOST_NO_EXCEPTIONS)
if(!p)boost::throw_exception(std::runtime_error("null indirection"));
#endif
return *p;
}
T* operator->()const{return p;}
non_raw_pointer& operator++(){++p;return *this;}
non_raw_pointer operator++(int){non_raw_pointer t(*this);++p;return t;}
non_raw_pointer& operator--(){--p;return *this;}
non_raw_pointer operator--(int){non_raw_pointer t(*this);--p;return t;}
non_raw_pointer& operator+=(std::ptrdiff_t n){p+=n;return *this;}
non_raw_pointer& operator-=(std::ptrdiff_t n){p-=n;return *this;}
T& operator[](std::ptrdiff_t n)const{return p[n];}
T* raw_ptr()const{return p;}
private:
T* p;
};
template<typename T>
non_raw_pointer<T> operator+(const non_raw_pointer<T>& x,std::ptrdiff_t n)
{return non_raw_pointer<T>(x.raw_ptr()+n);}
template<typename T>
non_raw_pointer<T> operator+(std::ptrdiff_t n,const non_raw_pointer<T>& x)
{return non_raw_pointer<T>(n+x.raw_ptr());}
template<typename T>
non_raw_pointer<T> operator-(const non_raw_pointer<T>& x,std::ptrdiff_t n)
{return non_raw_pointer<T>(x.raw_ptr()-n);}
template<typename T>
std::ptrdiff_t operator-(
const non_raw_pointer<T>& x,const non_raw_pointer<T>& y)
{return x.raw_ptr()-y.raw_ptr();}
template<typename T>
bool operator==(const non_raw_pointer<T>& x,const non_raw_pointer<T>& y)
{return x.raw_ptr()==y.raw_ptr();}
template<typename T>
bool operator!=(const non_raw_pointer<T>& x,const non_raw_pointer<T>& y)
{return x.raw_ptr()!=y.raw_ptr();}
template<typename T>
bool operator<(const non_raw_pointer<T>& x,const non_raw_pointer<T>& y)
{return x.raw_ptr()<y.raw_ptr();}
template<typename T>
bool operator>(const non_raw_pointer<T>& x,const non_raw_pointer<T>& y)
{return x.raw_ptr()>y.raw_ptr();}
template<typename T>
bool operator>=(const non_raw_pointer<T>& x,const non_raw_pointer<T>& y)
{return x.raw_ptr()>=y.raw_ptr();}
template<typename T>
bool operator<=(const non_raw_pointer<T>& x,const non_raw_pointer<T>& y)
{return x.raw_ptr()<=y.raw_ptr();}
template<typename T>
class non_std_allocator
{
public:
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef non_raw_pointer<T> pointer;
typedef non_raw_pointer<const T> const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef T value_type;
template<class U>struct rebind{typedef non_std_allocator<U> other;};
non_std_allocator(){}
non_std_allocator(const non_std_allocator<T>&){}
template<class U>non_std_allocator(const non_std_allocator<U>&,int=0){}
pointer allocate(size_type n)
{
return pointer((T*)(new char[n*sizeof(T)]));
}
void deallocate(pointer p,size_type)
{
delete[](char *)&*p;
}
size_type max_size() const{return (size_type )(-1);}
friend bool operator==(const non_std_allocator&,const non_std_allocator&)
{
return true;
}
friend bool operator!=(const non_std_allocator&,const non_std_allocator&)
{
return false;
}
};
#endif

View File

@@ -0,0 +1,78 @@
/* Used in Boost.MultiIndex tests.
*
* Copyright 2003-2010 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_TEST_PAIR_OF_INTS_HPP
#define BOOST_MULTI_INDEX_TEST_PAIR_OF_INTS_HPP
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <boost/serialization/nvp.hpp>
struct pair_of_ints
{
pair_of_ints(int first_=0,int second_=0):first(first_),second(second_){}
bool operator==(const pair_of_ints& x)const
{
return first==x.first&&second==x.second;
}
bool operator!=(const pair_of_ints& x)const{return !(*this==x);}
int first,second;
};
inline void increment_first(pair_of_ints& p)
{
++p.first;
}
inline void increment_second(pair_of_ints& p)
{
++p.second;
}
inline void increment_int(int& x)
{
++x;
}
inline int decrement_first(pair_of_ints& p)
{
return --p.first;
}
inline int decrement_second(pair_of_ints& p)
{
return --p.second;
}
inline int decrement_int(int& x)
{
return --x;
}
#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
namespace boost{
namespace serialization{
#endif
template<class Archive>
void serialize(Archive& ar,pair_of_ints& p,const unsigned int)
{
ar&boost::serialization::make_nvp("first",p.first);
ar&boost::serialization::make_nvp("second",p.second);
}
#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
} /* namespace serialization */
} /* namespace boost*/
#endif
#endif

View File

@@ -0,0 +1,49 @@
/* Used in Boost.MultiIndex tests.
*
* Copyright 2003-2008 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_TEST_PRE_MULTI_INDEX_HPP
#define BOOST_MULTI_INDEX_TEST_PRE_MULTI_INDEX_HPP
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <boost/detail/workaround.hpp>
#include <boost/multi_index/safe_mode_errors.hpp>
#if defined(__GNUC__)&&defined(__APPLE__)&&\
(__GNUC__==4)&&(__GNUC_MINOR__==0)&&(__APPLE_CC__<=4061)
/* Darwin 8.1 includes a prerelease version of GCC 4.0 that, alas,
* has a regression as described in
* http://gcc.gnu.org/bugzilla/show_bug.cgi?id=17435
* This compiler bug (fixed in the official 4.0 release) ruins the
* mechanisms upon which invariant-checking scope guards are built,
* so we can't set the invariant checking mode.
*/
#else
#define BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING
#endif
#define BOOST_MULTI_INDEX_ENABLE_SAFE_MODE
#if BOOST_WORKAROUND(__IBMCPP__,<=600)
#pragma info(nolan) /* suppress warnings about offsetof with non-POD types */
#endif
struct safe_mode_exception
{
safe_mode_exception(boost::multi_index::safe_mode::error_code error_code_):
error_code(error_code_)
{}
boost::multi_index::safe_mode::error_code error_code;
};
#define BOOST_MULTI_INDEX_SAFE_MODE_ASSERT(expr,error_code) \
if(!(expr)){throw safe_mode_exception(error_code);}
#endif

View File

@@ -0,0 +1,61 @@
/* Boost.MultiIndex test suite.
*
* Copyright 2003-2015 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
#include <boost/detail/lightweight_test.hpp>
#include "test_basic.hpp"
#include "test_capacity.hpp"
#include "test_comparison.hpp"
#include "test_composite_key.hpp"
#include "test_conv_iterators.hpp"
#include "test_copy_assignment.hpp"
#include "test_hash_ops.hpp"
#include "test_iterators.hpp"
#include "test_key_extractors.hpp"
#include "test_list_ops.hpp"
#include "test_modifiers.hpp"
#include "test_mpl_ops.hpp"
#include "test_observers.hpp"
#include "test_projection.hpp"
#include "test_range.hpp"
#include "test_rank_ops.hpp"
#include "test_rearrange.hpp"
#include "test_safe_mode.hpp"
#include "test_serialization.hpp"
#include "test_set_ops.hpp"
#include "test_special_set_ops.hpp"
#include "test_update.hpp"
int main()
{
test_basic();
test_capacity();
test_comparison();
test_composite_key();
test_conv_iterators();
test_copy_assignment();
test_hash_ops();
test_iterators();
test_key_extractors();
test_list_ops();
test_modifiers();
test_mpl_ops();
test_observers();
test_projection();
test_range();
test_rank_ops();
test_rearrange();
test_safe_mode();
test_serialization();
test_set_ops();
test_special_set_ops();
test_update();
return boost::report_errors();
}

View File

@@ -0,0 +1,81 @@
/* Boost.MultiIndex basic test.
*
* Copyright 2003-2013 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
#include "test_basic.hpp"
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <algorithm>
#include <vector>
#include "pre_multi_index.hpp"
#include "employee.hpp"
#include <boost/detail/lightweight_test.hpp>
using namespace boost::multi_index;
struct less_by_employee_age
{
bool operator()(const employee& e1,const employee& e2)const
{
return e1.age<e2.age;
}
};
void test_basic()
{
employee_set es;
std::vector<employee> v;
#if defined(BOOST_NO_MEMBER_TEMPLATES)
employee_set_by_name& i1=get<by_name>(es);
#else
employee_set_by_name& i1=es.get<by_name>();
#endif
const employee_set_by_age& i2=get<2>(es);
employee_set_as_inserted& i3=get<3>(es);
employee_set_by_ssn& i4=get<ssn>(es);
employee_set_randomly& i5=get<randomly>(es);
es.insert(employee(0,"Joe",31,1123));
es.insert(employee(5,"Anna",41,1123)); /* clash*/
i1.insert(employee(1,"Robert",27,5601));
es.insert(employee(2,"John",40,7889));
i3.push_back(employee(3,"Albert",20,9012));
i4.insert(employee(4,"John",57,1002));
i5.push_back(employee(0,"Andrew",60,2302)); /* clash */
v.push_back(employee(0,"Joe",31,1123));
v.push_back(employee(1,"Robert",27,5601));
v.push_back(employee(2,"John",40,7889));
v.push_back(employee(3,"Albert",20,9012));
v.push_back(employee(4,"John",57,1002));
{
/* by insertion order */
BOOST_TEST(std::equal(i3.begin(),i3.end(),v.begin()));
BOOST_TEST(std::equal(i5.begin(),i5.end(),v.begin()));
}
{
/* by id */
std::sort(v.begin(),v.end());
BOOST_TEST(std::equal(es.begin(),es.end(),v.begin()));
}
{
/* by age */
std::sort(v.begin(),v.end(),less_by_employee_age());
BOOST_TEST(std::equal(i2.begin(),i2.end(),v.begin()));
}
}

View File

@@ -0,0 +1,11 @@
/* Boost.MultiIndex basic test.
*
* Copyright 2003-2008 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
void test_basic();

View File

@@ -0,0 +1,18 @@
/* Boost.MultiIndex basic test.
*
* Copyright 2003-2013 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
#include <boost/detail/lightweight_test.hpp>
#include "test_basic.hpp"
int main()
{
test_basic();
return boost::report_errors();
}

View File

@@ -0,0 +1,97 @@
/* Boost.MultiIndex test for capacity memfuns.
*
* Copyright 2003-2015 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
#include "test_capacity.hpp"
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include "pre_multi_index.hpp"
#include "employee.hpp"
#include <boost/detail/lightweight_test.hpp>
using namespace boost::multi_index;
void test_capacity()
{
employee_set es;
es.insert(employee(0,"Joe",31,1123));
es.insert(employee(1,"Robert",27,5601));
es.insert(employee(2,"John",40,7889));
es.insert(employee(3,"Albert",20,9012));
es.insert(employee(4,"John",57,1002));
BOOST_TEST(!es.empty());
BOOST_TEST(es.size()==5);
BOOST_TEST(es.size()<=es.max_size());
es.erase(es.begin());
BOOST_TEST(!get<name>(es).empty());
BOOST_TEST(get<name>(es).size()==4);
BOOST_TEST(get<name>(es).size()<=get<name>(es).max_size());
es.erase(es.begin());
BOOST_TEST(!get<as_inserted>(es).empty());
BOOST_TEST(get<as_inserted>(es).size()==3);
BOOST_TEST(get<as_inserted>(es).size()<=get<as_inserted>(es).max_size());
multi_index_container<int,indexed_by<sequenced<> > > ss;
ss.resize(10);
BOOST_TEST(ss.size()==10);
BOOST_TEST(ss.size()<=ss.max_size());
ss.resize(20,666);
BOOST_TEST(ss.size()==20);
BOOST_TEST(ss.back()==666);
ss.resize(5,10);
BOOST_TEST(ss.size()==5);
ss.resize(4);
BOOST_TEST(ss.size()==4);
multi_index_container<int,indexed_by<random_access<> > > rs;
rs.resize(10);
BOOST_TEST(rs.size()==10);
BOOST_TEST(rs.size()<=rs.max_size());
BOOST_TEST(rs.size()<=rs.capacity());
rs.resize(20,666);
BOOST_TEST(rs.size()==20);
BOOST_TEST(rs.back()==666);
BOOST_TEST(rs.size()<=rs.capacity());
employee_set::size_type c=rs.capacity();
rs.resize(10,20);
BOOST_TEST(rs.size()==10);
BOOST_TEST(rs.capacity()==c);
rs.resize(5);
BOOST_TEST(rs.size()==5);
BOOST_TEST(rs.capacity()==c);
rs.reserve(100);
BOOST_TEST(rs.size()==5);
BOOST_TEST(rs.capacity()>=100);
c=rs.capacity();
rs.reserve(99);
BOOST_TEST(rs.size()==5);
BOOST_TEST(rs.capacity()==c);
rs.shrink_to_fit();
BOOST_TEST(rs.size()==5);
BOOST_TEST(rs.capacity()==rs.size());
rs.clear();
rs.shrink_to_fit();
BOOST_TEST(rs.capacity()==0);
}

View File

@@ -0,0 +1,11 @@
/* Boost.MultiIndex test for capacity memfuns.
*
* Copyright 2003-2008 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
void test_capacity();

View File

@@ -0,0 +1,19 @@
/* Boost.MultiIndex test for capacity memfuns.
*
* Copyright 2003-2013 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
#include <boost/detail/lightweight_test.hpp>
#include "test_capacity.hpp"
int main()
{
test_capacity();
return boost::report_errors();
}

View File

@@ -0,0 +1,151 @@
/* Boost.MultiIndex test for comparison functions.
*
* Copyright 2003-2013 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
#include "test_comparison.hpp"
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include "pre_multi_index.hpp"
#include "employee.hpp"
#include "pair_of_ints.hpp"
#include <boost/detail/lightweight_test.hpp>
using namespace boost::multi_index;
template<typename Value>
struct lookup_list{
typedef multi_index_container<
Value,
indexed_by<
sequenced<>,
ordered_non_unique<identity<Value> >
>
> type;
};
template<typename Value>
struct lookup_vector{
typedef multi_index_container<
Value,
indexed_by<
random_access<>,
ordered_non_unique<identity<Value> >
>
> type;
};
void test_comparison()
{
employee_set es;
employee_set_by_name& i1=get<1>(es);
employee_set_by_age& i2=get<2>(es);
employee_set_as_inserted& i3=get<3>(es);
employee_set_by_ssn& i4=get<4>(es);
employee_set_randomly& i5=get<5>(es);
es.insert(employee(0,"Joe",31,1123));
es.insert(employee(1,"Robert",27,5601));
es.insert(employee(2,"John",40,7889));
es.insert(employee(3,"Albert",20,9012));
es.insert(employee(4,"John",57,1002));
employee_set es2;
employee_set_by_name& i12=get<by_name>(es2);
employee_set_by_age& i22=get<age>(es2);
employee_set_as_inserted& i32=get<3>(es2);
employee_set_by_ssn& i42=get<4>(es2);
employee_set_randomly& i52=get<5>(es2);
es2.insert(employee(0,"Joe",31,1123));
es2.insert(employee(1,"Robert",27,5601));
es2.insert(employee(2,"John",40,7889));
es2.insert(employee(3,"Albert",20,9012));
BOOST_TEST(es==es&&es<=es&&es>=es&&
i12==i12&&
i22==i22&&i22<=i22&&i22>=i22&&
i32==i32&&i32<=i32&&i32>=i32&&
i42==i42&&
i52==i52&&i52<=i52&&i52>=i52);
BOOST_TEST(es!=es2&&es2<es&&es>es2&&!(es<=es2)&&!(es2>=es));
BOOST_TEST(i1!=i12);
BOOST_TEST(i2!=i22&&i22<i2&&i2>i22&&!(i2<=i22)&&!(i22>=i2));
BOOST_TEST(i3!=i32&&i32<i3&&i3>i32&&!(i3<=i32)&&!(i32>=i3));
BOOST_TEST(i4!=i42);
BOOST_TEST(i5!=i52&&i52<i5&&i5>i52&&!(i5<=i52)&&!(i52>=i5));
multi_index_container<
pair_of_ints,
indexed_by<
hashed_non_unique<BOOST_MULTI_INDEX_MEMBER(pair_of_ints,int,first)>
>
> hc1,hc2;
hc1.insert(pair_of_ints(0,0));
hc1.insert(pair_of_ints(0,1));
hc1.insert(pair_of_ints(0,2));
hc1.insert(pair_of_ints(0,3));
hc1.insert(pair_of_ints(1,0));
hc1.insert(pair_of_ints(1,1));
hc2.insert(pair_of_ints(0,2));
hc2.insert(pair_of_ints(0,1));
hc2.insert(pair_of_ints(1,1));
hc2.insert(pair_of_ints(1,0));
hc2.insert(pair_of_ints(0,3));
hc2.insert(pair_of_ints(0,0));
BOOST_TEST(hc1==hc2);
hc1.insert(pair_of_ints(0,4));
hc2.insert(pair_of_ints(0,5));
BOOST_TEST(hc1!=hc2);
lookup_list<int>::type l1;
lookup_list<char>::type l2;
lookup_vector<char>::type l3;
lookup_list<long>::type l4;
lookup_vector<long>::type l5;
l1.push_back(3);
l1.push_back(4);
l1.push_back(5);
l1.push_back(1);
l1.push_back(2);
l2.push_back(char(3));
l2.push_back(char(4));
l2.push_back(char(5));
l2.push_back(char(1));
l2.push_back(char(2));
l3.push_back(char(3));
l3.push_back(char(4));
l3.push_back(char(5));
l3.push_back(char(1));
l3.push_back(char(2));
l4.push_back(long(3));
l4.push_back(long(4));
l4.push_back(long(5));
l4.push_back(long(1));
l5.push_back(long(3));
l5.push_back(long(4));
l5.push_back(long(5));
l5.push_back(long(1));
BOOST_TEST(l1==l2&&l1<=l2&&l1>=l2);
BOOST_TEST(
get<1>(l1)==get<1>(l2)&&get<1>(l1)<=get<1>(l2)&&get<1>(l1)>=get<1>(l2));
BOOST_TEST(
get<1>(l1)==get<1>(l3)&&get<1>(l1)<=get<1>(l3)&&get<1>(l1)>=get<1>(l3));
BOOST_TEST(l1!=l4&&l4<l1&&l1>l4);
BOOST_TEST(
get<1>(l1)!=get<1>(l4)&&get<1>(l1)<get<1>(l4)&&get<1>(l4)>get<1>(l1));
BOOST_TEST(l3!=l5&&l5<l3&&l3>l5);
BOOST_TEST(
get<1>(l3)!=get<1>(l5)&&get<1>(l3)<get<1>(l5)&&get<1>(l5)>get<1>(l3));
}

View File

@@ -0,0 +1,11 @@
/* Boost.MultiIndex test for comparison functions.
*
* Copyright 2003-2008 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
void test_comparison();

View File

@@ -0,0 +1,19 @@
/* Boost.MultiIndex test for comparison functions.
*
* Copyright 2003-2013 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
#include <boost/detail/lightweight_test.hpp>
#include "test_comparison.hpp"
int main()
{
test_comparison();
return boost::report_errors();
}

View File

@@ -0,0 +1,670 @@
/* Boost.MultiIndex test for composite_key.
*
* Copyright 2003-2014 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
#include "test_composite_key.hpp"
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <boost/detail/lightweight_test.hpp>
#include "pre_multi_index.hpp"
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/composite_key.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/preprocessor/repetition/enum_binary_params.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
using namespace boost::multi_index;
using namespace boost::tuples;
struct is_composite_key_result_helper
{
typedef char yes;
struct no{char m[2];};
static no test(void*);
template<typename CompositeKey>
static yes test(composite_key_result<CompositeKey>*);
};
template<typename T>
struct is_composite_key_result
{
typedef is_composite_key_result_helper helper;
BOOST_STATIC_CONSTANT(bool,
value=(
sizeof(helper::test((T*)0))==
sizeof(typename helper::yes)));
};
template<typename CompositeKeyResult>
struct composite_key_result_length
{
BOOST_STATIC_CONSTANT(int,
value=boost::tuples::length<
BOOST_DEDUCED_TYPENAME
CompositeKeyResult::composite_key_type::key_extractor_tuple
>::value);
};
#if !defined(BOOST_NO_CXX11_HDR_TUPLE)&&\
!defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
struct is_boost_tuple_helper
{
typedef char yes;
struct no{char m[2];};
static no test(void*);
template<BOOST_PP_ENUM_PARAMS(10,typename T)>
static yes test(boost::tuple<BOOST_PP_ENUM_PARAMS(10,T)>*);
};
template<typename T>
struct is_boost_tuple
{
typedef is_boost_tuple_helper helper;
BOOST_STATIC_CONSTANT(bool,
value=(
sizeof(helper::test((T*)0))==
sizeof(typename helper::yes)));
};
template<typename T>
struct composite_object_length
{
typedef typename boost::mpl::if_c<
is_composite_key_result<T>::value,
composite_key_result_length<T>,
typename boost::mpl::if_c<
is_boost_tuple<T>::value,
boost::tuples::length<T>,
std::tuple_size<T>
>::type
>::type type;
BOOST_STATIC_CONSTANT(int,value=type::value);
};
#else
template<typename T>
struct composite_object_length
{
typedef typename boost::mpl::if_c<
is_composite_key_result<T>::value,
composite_key_result_length<T>,
boost::tuples::length<T>
>::type type;
BOOST_STATIC_CONSTANT(int,value=type::value);
};
#endif
template<typename CompositeKeyResult,typename T2>
struct comparison_equal_length
{
static bool is_less(const CompositeKeyResult& x,const T2& y)
{
composite_key_result_equal_to<CompositeKeyResult> eq;
composite_key_result_less<CompositeKeyResult> lt;
composite_key_result_greater<CompositeKeyResult> gt;
std::equal_to<CompositeKeyResult> std_eq;
std::less<CompositeKeyResult> std_lt;
std::greater<CompositeKeyResult> std_gt;
return (x< y) && !(y< x)&&
!(x==y) && !(y==x)&&
(x!=y) && (y!=x)&&
!(x> y) && (y> x)&&
!(x>=y) && (y>=x)&&
(x<=y) && !(y<=x)&&
!eq(x,y) && !eq(y,x)&&
lt(x,y) && !lt(y,x)&&
!gt(x,y) && gt(y,x)&&
!std_eq(x,y) && !std_eq(y,x)&&
std_lt(x,y) && !std_lt(y,x)&&
!std_gt(x,y) && std_gt(y,x);
}
static bool is_greater(const CompositeKeyResult& x,const T2& y)
{
composite_key_result_equal_to<CompositeKeyResult> eq;
composite_key_result_less<CompositeKeyResult> lt;
composite_key_result_greater<CompositeKeyResult> gt;
std::equal_to<CompositeKeyResult> std_eq;
std::less<CompositeKeyResult> std_lt;
std::greater<CompositeKeyResult> std_gt;
return !(x< y) && (y< x)&&
!(x==y) && !(y==x)&&
(x!=y) && (y!=x)&&
(x> y) && !(y> x)&&
(x>=y) && !(y>=x)&&
!(x<=y) && (y<=x)&&
!eq(x,y) && !eq(y,x)&&
!lt(x,y) && lt(y,x)&&
gt(x,y) && !gt(y,x)&&
!std_eq(x,y) && !std_eq(y,x)&&
!std_lt(x,y) && std_lt(y,x)&&
std_gt(x,y) && !std_gt(y,x);
}
static bool is_equiv(const CompositeKeyResult& x,const T2& y)
{
composite_key_result_equal_to<CompositeKeyResult> eq;
composite_key_result_less<CompositeKeyResult> lt;
composite_key_result_greater<CompositeKeyResult> gt;
std::equal_to<CompositeKeyResult> std_eq;
std::less<CompositeKeyResult> std_lt;
std::greater<CompositeKeyResult> std_gt;
return !(x< y) && !(y< x)&&
(x==y) && (y==x)&&
!(x!=y) && !(y!=x)&&
!(x> y) && !(y> x)&&
(x>=y) && (y>=x)&&
(x<=y) && (y<=x)&&
eq(x,y) && eq(y,x)&&
!lt(x,y) && !lt(y,x)&&
!gt(x,y) && !gt(y,x)&&
std_eq(x,y) && std_eq(y,x)&&
!std_lt(x,y) && !std_lt(y,x)&&
!std_gt(x,y) && !std_gt(y,x);
}
};
template<typename CompositeKeyResult,typename T2>
struct comparison_different_length
{
static bool is_less(const CompositeKeyResult& x,const T2& y)
{
composite_key_result_less<CompositeKeyResult> lt;
composite_key_result_greater<CompositeKeyResult> gt;
std::less<CompositeKeyResult> std_lt;
std::greater<CompositeKeyResult> std_gt;
return (x< y) && !(y< x)&&
!(x> y) && (y> x)&&
!(x>=y) && (y>=x)&&
(x<=y) && !(y<=x)&&
lt(x,y) && !lt(y,x)&&
!gt(x,y) && gt(y,x)&&
std_lt(x,y) && !std_lt(y,x)&&
!std_gt(x,y) && std_gt(y,x);
}
static bool is_greater(const CompositeKeyResult& x,const T2& y)
{
composite_key_result_less<CompositeKeyResult> lt;
composite_key_result_greater<CompositeKeyResult> gt;
std::less<CompositeKeyResult> std_lt;
std::greater<CompositeKeyResult> std_gt;
return !(x< y) && (y< x)&&
(x> y) && !(y> x)&&
(x>=y) && !(y>=x)&&
!(x<=y) && (y<=x)&&
!lt(x,y) && lt(y,x)&&
gt(x,y) && !gt(y,x)&&
!std_lt(x,y) && std_lt(y,x)&&
std_gt(x,y) && !std_gt(y,x);
}
static bool is_equiv(const CompositeKeyResult& x,const T2& y)
{
composite_key_result_less<CompositeKeyResult> lt;
composite_key_result_greater<CompositeKeyResult> gt;
std::less<CompositeKeyResult> std_lt;
std::greater<CompositeKeyResult> std_gt;
return !(x< y) && !(y< x)&&
!(x> y) && !(y> x)&&
(x>=y) && (y>=x)&&
(x<=y) && (y<=x)&&
!lt(x,y) && !lt(y,x)&&
!gt(x,y) && !gt(y,x)&&
!std_lt(x,y) && !std_lt(y,x)&&
!std_gt(x,y) && !std_gt(y,x);
}
};
template<typename CompositeKeyResult,typename T2>
struct comparison_helper:
boost::mpl::if_c<
composite_key_result_length<CompositeKeyResult>::value==
composite_object_length<T2>::value,
comparison_equal_length<CompositeKeyResult,T2>,
comparison_different_length<CompositeKeyResult,T2>
>::type
{
};
template<typename CompositeKeyResult,typename T2>
static bool is_less(const CompositeKeyResult& x,const T2& y)
{
return comparison_helper<CompositeKeyResult,T2>::is_less(x,y);
}
template<typename CompositeKeyResult,typename T2>
static bool is_greater(const CompositeKeyResult& x,const T2& y)
{
return comparison_helper<CompositeKeyResult,T2>::is_greater(x,y);
}
template<typename CompositeKeyResult,typename T2>
static bool is_equiv(const CompositeKeyResult& x,const T2& y)
{
return comparison_helper<CompositeKeyResult,T2>::is_equiv(x,y);
}
template<typename T1,typename T2,typename Compare>
static bool is_less(const T1& x,const T2& y,const Compare& c)
{
return c(x,y)&&!c(y,x);
}
template<typename T1,typename T2,typename Compare>
static bool is_greater(const T1& x,const T2& y,const Compare& c)
{
return c(y,x)&&!c(x,y);
}
template<typename T1,typename T2,typename Compare>
static bool is_equiv(const T1& x,const T2& y,const Compare& c)
{
return !c(x,y)&&!c(y,x);
}
template<typename T1,typename T2,typename Compare,typename Equiv>
static bool is_less(
const T1& x,const T2& y,const Compare& c,const Equiv& eq)
{
return c(x,y)&&!c(y,x)&&!eq(x,y)&&!eq(y,x);
}
template<typename T1,typename T2,typename Compare,typename Equiv>
static bool is_greater(
const T1& x,const T2& y,const Compare& c,const Equiv& eq)
{
return c(y,x)&&!c(x,y)&&!eq(x,y)&&!eq(y,x);
}
template<typename T1,typename T2,typename Compare,typename Equiv>
static bool is_equiv(
const T1& x,const T2& y,const Compare& c,const Equiv& eq)
{
return !c(x,y)&&!c(y,x)&&eq(x,y)&&eq(y,x);
}
struct xyz
{
xyz(int x_=0,int y_=0,int z_=0):x(x_),y(y_),z(z_){}
int x;
int y;
int z;
};
struct modulo_equal
{
modulo_equal(int i):i_(i){}
bool operator ()(int x,int y)const{return (x%i_)==(y%i_);}
private:
int i_;
};
struct xystr
{
xystr(int x_=0,int y_=0,std::string str_=0):x(x_),y(y_),str(str_){}
int x;
int y;
std::string str;
};
#define TUPLE_MAKER_CREATE(z,n,tuple) \
template<BOOST_PP_ENUM_PARAMS(n,typename T)> \
static tuple<BOOST_PP_ENUM_PARAMS(n,T)> \
create(BOOST_PP_ENUM_BINARY_PARAMS(n,const T,& t)){ \
return tuple<BOOST_PP_ENUM_PARAMS(n,T)>( \
BOOST_PP_ENUM_PARAMS(n,t)); \
}
#define DEFINE_TUPLE_MAKER(name,tuple) \
struct name \
{ \
static tuple<> create(){return tuple<>();} \
BOOST_PP_REPEAT_FROM_TO(1,5,TUPLE_MAKER_CREATE,tuple) \
};
DEFINE_TUPLE_MAKER(boost_tuple_maker,boost::tuple)
#if !defined(BOOST_NO_CXX11_HDR_TUPLE)&&\
!defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
DEFINE_TUPLE_MAKER(std_tuple_maker,std::tuple)
#endif
#undef DEFINE_TUPLE_MAKER
#undef TUPLE_MAKER_CREATE
template<typename TupleMaker>
void test_composite_key_template()
{
typedef composite_key<
xyz,
BOOST_MULTI_INDEX_MEMBER(xyz,int,x),
BOOST_MULTI_INDEX_MEMBER(xyz,int,y),
BOOST_MULTI_INDEX_MEMBER(xyz,int,z)
> ckey_t1;
typedef multi_index_container<
xyz,
indexed_by<
ordered_unique<ckey_t1>
>
> indexed_t1;
indexed_t1 mc1;
mc1.insert(xyz(0,0,0));
mc1.insert(xyz(0,0,1));
mc1.insert(xyz(0,1,0));
mc1.insert(xyz(0,1,1));
mc1.insert(xyz(1,0,0));
mc1.insert(xyz(1,0,1));
mc1.insert(xyz(1,1,0));
mc1.insert(xyz(1,1,1));
BOOST_TEST(mc1.size()==8);
BOOST_TEST(
std::distance(
mc1.find(mc1.key_extractor()(xyz(0,0,0))),
mc1.find(mc1.key_extractor()(xyz(1,0,0))))==4);
BOOST_TEST(
std::distance(
mc1.find(TupleMaker::create(0,0,0)),
mc1.find(TupleMaker::create(1,0,0)))==4);
BOOST_TEST(
std::distance(
mc1.lower_bound(TupleMaker::create(0,0)),
mc1.upper_bound(TupleMaker::create(1,0)))==6);
#if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING)
BOOST_TEST(
std::distance(
mc1.lower_bound(1),
mc1.upper_bound(1))==4);
#endif
ckey_t1 ck1;
ckey_t1 ck2(ck1);
ckey_t1 ck3(
boost::make_tuple(
BOOST_MULTI_INDEX_MEMBER(xyz,int,x)(),
BOOST_MULTI_INDEX_MEMBER(xyz,int,y)(),
BOOST_MULTI_INDEX_MEMBER(xyz,int,z)()));
ckey_t1 ck4(get<0>(ck1.key_extractors()));
ck3=ck3; /* prevent unused var */
get<2>(ck4.key_extractors())=
get<2>(ck2.key_extractors());
BOOST_TEST(is_equiv (ck1(xyz(0,0,0)),ck2(xyz(0,0,0))));
BOOST_TEST(is_less (ck1(xyz(0,0,1)),ck2(xyz(0,1,0))));
BOOST_TEST(is_greater(ck1(xyz(0,0,1)),ck2(xyz(0,0,0))));
BOOST_TEST(is_equiv (ck1(xyz(0,0,0)),TupleMaker::create(0)));
BOOST_TEST(is_less (ck1(xyz(0,0,0)),TupleMaker::create(1)));
BOOST_TEST(is_greater(ck1(xyz(0,0,0)),TupleMaker::create(-1)));
BOOST_TEST(is_equiv (ck1(xyz(0,0,0)),TupleMaker::create(0,0)));
BOOST_TEST(is_less (ck1(xyz(0,0,0)),TupleMaker::create(0,1)));
BOOST_TEST(is_greater(ck1(xyz(0,0,0)),TupleMaker::create(0,-1)));
BOOST_TEST(is_equiv (ck1(xyz(0,0,0)),TupleMaker::create(0,0,0)));
BOOST_TEST(is_less (ck1(xyz(0,0,0)),TupleMaker::create(0,0,1)));
BOOST_TEST(is_greater(ck1(xyz(0,0,0)),TupleMaker::create(0,0,-1)));
BOOST_TEST(is_equiv (ck1(xyz(0,0,0)),TupleMaker::create(0,0,0,1)));
typedef composite_key_result_less<ckey_t1::result_type> ckey_comp_t1;
typedef composite_key_result_equal_to<ckey_t1::result_type> ckey_eq_t1;
ckey_comp_t1 cp1;
ckey_eq_t1 eq1;
BOOST_TEST(is_equiv (ck1(xyz(0,0,0)),ck2(xyz(0,0,0)),cp1,eq1));
BOOST_TEST(is_less (ck1(xyz(0,0,1)),ck2(xyz(0,1,0)),cp1,eq1));
BOOST_TEST(is_greater(ck1(xyz(0,0,1)),ck2(xyz(0,0,0)),cp1,eq1));
BOOST_TEST(is_equiv (ck1(xyz(0,0,0)),TupleMaker::create(0),cp1));
BOOST_TEST(is_less (ck1(xyz(0,0,0)),TupleMaker::create(1),cp1));
BOOST_TEST(is_greater(ck1(xyz(0,0,0)),TupleMaker::create(-1),cp1));
#if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING)
BOOST_TEST(is_equiv (ck1(xyz(0,0,0)),0,cp1));
BOOST_TEST(is_less (ck1(xyz(0,0,0)),1,cp1));
BOOST_TEST(is_greater(ck1(xyz(0,0,0)),-1,cp1));
#endif
BOOST_TEST(is_equiv (ck1(xyz(0,0,0)),TupleMaker::create(0,0),cp1));
BOOST_TEST(is_less (ck1(xyz(0,0,0)),TupleMaker::create(0,1),cp1));
BOOST_TEST(is_greater(ck1(xyz(0,0,0)),TupleMaker::create(0,-1),cp1));
BOOST_TEST(is_equiv (ck1(xyz(0,0,0)),TupleMaker::create(0,0,0),cp1,eq1));
BOOST_TEST(is_less (ck1(xyz(0,0,0)),TupleMaker::create(0,0,1),cp1,eq1));
BOOST_TEST(is_greater(ck1(xyz(0,0,0)),TupleMaker::create(0,0,-1),cp1,eq1));
typedef composite_key_result_greater<ckey_t1::result_type> ckey_comp_t2;
ckey_comp_t2 cp2;
BOOST_TEST(is_equiv (ck1(xyz(0,0,0)),ck2(xyz(0,0,0)),cp2));
BOOST_TEST(is_greater(ck1(xyz(0,0,1)),ck2(xyz(0,1,0)),cp2));
BOOST_TEST(is_less (ck1(xyz(0,0,1)),ck2(xyz(0,0,0)),cp2));
BOOST_TEST(is_equiv (ck1(xyz(0,0,0)),TupleMaker::create(0),cp2));
BOOST_TEST(is_greater(ck1(xyz(0,0,0)),TupleMaker::create(1),cp2));
BOOST_TEST(is_less (ck1(xyz(0,0,0)),TupleMaker::create(-1),cp2));
BOOST_TEST(is_equiv (ck1(xyz(0,0,0)),TupleMaker::create(0,0),cp2));
BOOST_TEST(is_greater(ck1(xyz(0,0,0)),TupleMaker::create(0,1),cp2));
BOOST_TEST(is_less (ck1(xyz(0,0,0)),TupleMaker::create(0,-1),cp2));
BOOST_TEST(is_equiv (ck1(xyz(0,0,0)),TupleMaker::create(0,0,0),cp2));
BOOST_TEST(is_greater(ck1(xyz(0,0,0)),TupleMaker::create(0,0,1),cp2));
BOOST_TEST(is_less (ck1(xyz(0,0,0)),TupleMaker::create(0,0,-1),cp2));
typedef composite_key_equal_to<
modulo_equal,
modulo_equal,
std::equal_to<int>,
std::equal_to<int>
> ckey_eq_t2;
ckey_eq_t2 eq2(
boost::make_tuple(
modulo_equal(2),
modulo_equal(3),
std::equal_to<int>(),
std::equal_to<int>()));
ckey_eq_t2 eq3(eq2);
ckey_eq_t2 eq4(
get<0>(eq3.key_eqs()),
get<1>(eq3.key_eqs()));
eq3=eq4; /* prevent unused var */
eq4=eq3; /* prevent unused var */
BOOST_TEST( eq2(ck1(xyz(0,0,0)),ck1(xyz(0,0,0))));
BOOST_TEST(!eq2(ck1(xyz(0,1,0)),ck1(xyz(0,0,0))));
BOOST_TEST(!eq2(ck1(xyz(0,2,0)),ck1(xyz(0,0,0))));
BOOST_TEST( eq2(ck1(xyz(0,3,0)),ck1(xyz(0,0,0))));
BOOST_TEST(!eq2(ck1(xyz(1,0,0)),ck1(xyz(0,0,0))));
BOOST_TEST(!eq2(ck1(xyz(1,1,0)),ck1(xyz(0,0,0))));
BOOST_TEST(!eq2(ck1(xyz(1,2,0)),ck1(xyz(0,0,0))));
BOOST_TEST(!eq2(ck1(xyz(1,3,0)),ck1(xyz(0,0,0))));
BOOST_TEST( eq2(ck1(xyz(2,0,0)),ck1(xyz(0,0,0))));
BOOST_TEST(!eq2(ck1(xyz(2,1,0)),ck1(xyz(0,0,0))));
BOOST_TEST(!eq2(ck1(xyz(2,2,0)),ck1(xyz(0,0,0))));
BOOST_TEST( eq2(ck1(xyz(2,3,0)),ck1(xyz(0,0,0))));
BOOST_TEST( eq2(TupleMaker::create(0,0,0),ck1(xyz(0,0,0))));
BOOST_TEST(!eq2(ck1(xyz(0,1,0)) ,TupleMaker::create(0,0,0)));
BOOST_TEST(!eq2(TupleMaker::create(0,2,0),ck1(xyz(0,0,0))));
BOOST_TEST( eq2(ck1(xyz(0,3,0)) ,TupleMaker::create(0,0,0)));
BOOST_TEST(!eq2(TupleMaker::create(1,0,0),ck1(xyz(0,0,0))));
BOOST_TEST(!eq2(ck1(xyz(1,1,0)) ,TupleMaker::create(0,0,0)));
BOOST_TEST(!eq2(TupleMaker::create(1,2,0),ck1(xyz(0,0,0))));
BOOST_TEST(!eq2(ck1(xyz(1,3,0)) ,TupleMaker::create(0,0,0)));
BOOST_TEST( eq2(TupleMaker::create(2,0,0),ck1(xyz(0,0,0))));
BOOST_TEST(!eq2(ck1(xyz(2,1,0)) ,TupleMaker::create(0,0,0)));
BOOST_TEST(!eq2(TupleMaker::create(2,2,0),ck1(xyz(0,0,0))));
BOOST_TEST( eq2(ck1(xyz(2,3,0)) ,TupleMaker::create(0,0,0)));
typedef composite_key_compare<
std::less<int>,
std::greater<int>, /* order reversed */
std::less<int>
> ckey_comp_t3;
ckey_comp_t3 cp3;
ckey_comp_t3 cp4(cp3);
ckey_comp_t3 cp5(
boost::make_tuple(
std::less<int>(),
std::greater<int>(),
std::less<int>()));
ckey_comp_t3 cp6(get<0>(cp3.key_comps()));
cp4=cp5; /* prevent unused var */
cp5=cp6; /* prevent unused var */
cp6=cp4; /* prevent unused var */
BOOST_TEST(is_equiv (ck1(xyz(0,0,0)),ck2(xyz(0,0,0)),cp3));
BOOST_TEST(is_greater(ck1(xyz(0,0,1)),ck2(xyz(0,1,0)),cp3));
BOOST_TEST(is_greater(ck1(xyz(0,0,1)),ck2(xyz(0,0,0)),cp3));
BOOST_TEST(is_equiv (ck1(xyz(0,0,0)),TupleMaker::create(0),cp3));
BOOST_TEST(is_less (ck1(xyz(0,0,0)),TupleMaker::create(1),cp3));
BOOST_TEST(is_greater(ck1(xyz(0,0,0)),TupleMaker::create(-1),cp3));
BOOST_TEST(is_equiv (ck1(xyz(0,0,0)),TupleMaker::create(0,0),cp3));
BOOST_TEST(is_less (ck1(xyz(0,0,0)),TupleMaker::create(0,-1),cp3));
BOOST_TEST(is_greater(ck1(xyz(0,0,0)),TupleMaker::create(0,1),cp3));
BOOST_TEST(is_equiv (ck1(xyz(0,0,0)),TupleMaker::create(0,0,0),cp3));
BOOST_TEST(is_less (ck1(xyz(0,0,0)),TupleMaker::create(0,0,1),cp3));
BOOST_TEST(is_greater(ck1(xyz(0,0,0)),TupleMaker::create(0,0,-1),cp3));
typedef composite_key<
xyz,
BOOST_MULTI_INDEX_MEMBER(xyz,int,y), /* members reversed */
BOOST_MULTI_INDEX_MEMBER(xyz,int,x)
> ckey_t2;
ckey_t2 ck5;
BOOST_TEST(is_equiv (ck1(xyz(0,0,1)),ck5(xyz(0,0,0))));
BOOST_TEST(is_less (ck1(xyz(0,0,0)),ck5(xyz(-1,1,0))));
BOOST_TEST(is_greater(ck1(xyz(0,0,0)),ck5(xyz(1,-1,0))));
BOOST_TEST(is_equiv (ck1(xyz(0,0,1)),ck5(xyz(0,0,0)),cp1));
BOOST_TEST(is_less (ck1(xyz(0,0,0)),ck5(xyz(-1,1,0)),cp1));
BOOST_TEST(is_greater(ck1(xyz(0,0,0)),ck5(xyz(1,-1,0)),cp1));
BOOST_TEST(is_equiv (ck1(xyz(0,0,1)),ck5(xyz(0,0,0)),cp2));
BOOST_TEST(is_greater(ck1(xyz(0,0,0)),ck5(xyz(-1,1,0)),cp2));
BOOST_TEST(is_less (ck1(xyz(0,0,0)),ck5(xyz(1,-1,0)),cp2));
BOOST_TEST(is_equiv (ck1(xyz(0,0,1)),ck5(xyz(0,0,0)),cp3));
BOOST_TEST(is_less (ck1(xyz(0,0,0)),ck5(xyz(-1,1,0)),cp3));
BOOST_TEST(is_greater(ck1(xyz(0,0,0)),ck5(xyz(1,-1,0)),cp3));
typedef multi_index_container<
xyz,
indexed_by<
hashed_unique<ckey_t1>
>
> indexed_t2;
indexed_t2 mc2;
mc2.insert(xyz(0,0,0));
mc2.insert(xyz(0,0,1));
mc2.insert(xyz(0,1,0));
mc2.insert(xyz(0,1,1));
mc2.insert(xyz(1,0,0));
mc2.insert(xyz(1,0,1));
mc2.insert(xyz(1,1,0));
mc2.insert(xyz(1,1,1));
mc2.insert(xyz(0,0,0));
mc2.insert(xyz(0,0,1));
mc2.insert(xyz(0,1,0));
mc2.insert(xyz(0,1,1));
mc2.insert(xyz(1,0,0));
mc2.insert(xyz(1,0,1));
mc2.insert(xyz(1,1,0));
mc2.insert(xyz(1,1,1));
BOOST_TEST(mc2.size()==8);
BOOST_TEST(mc2.find(TupleMaker::create(0,0,1))->z==1);
BOOST_TEST(ck1(*(mc2.find(TupleMaker::create(1,0,1))))==
TupleMaker::create(1,0,1));
typedef composite_key<
xystr,
BOOST_MULTI_INDEX_MEMBER(xystr,std::string,str),
BOOST_MULTI_INDEX_MEMBER(xystr,int,x),
BOOST_MULTI_INDEX_MEMBER(xystr,int,y)
> ckey_t3;
ckey_t3 ck6;
typedef composite_key_hash<
boost::hash<std::string>,
boost::hash<int>,
boost::hash<int>
> ckey_hash_t;
ckey_hash_t ch1;
ckey_hash_t ch2(ch1);
ckey_hash_t ch3(
boost::make_tuple(
boost::hash<std::string>(),
boost::hash<int>(),
boost::hash<int>()));
ckey_hash_t ch4(get<0>(ch1.key_hash_functions()));
ch2=ch3; /* prevent unused var */
ch3=ch4; /* prevent unused var */
ch4=ch2; /* prevent unused var */
BOOST_TEST(
ch1(ck6(xystr(0,0,"hello")))==
ch1(TupleMaker::create(std::string("hello"),0,0)));
BOOST_TEST(
ch1(ck6(xystr(4,5,"world")))==
ch1(TupleMaker::create(std::string("world"),4,5)));
typedef boost::hash<composite_key_result<ckey_t3> > ckeyres_hash_t;
ckeyres_hash_t crh;
BOOST_TEST(
ch1(ck6(xystr(0,0,"hello")))==crh(ck6(xystr(0,0,"hello"))));
BOOST_TEST(
ch1(ck6(xystr(4,5,"world")))==crh(ck6(xystr(4,5,"world"))));
}
void test_composite_key()
{
test_composite_key_template<boost_tuple_maker>();
#if !defined(BOOST_NO_CXX11_HDR_TUPLE)&&\
!defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
test_composite_key_template<std_tuple_maker>();
#endif
}

View File

@@ -0,0 +1,11 @@
/* Boost.MultiIndex test for composite_key.
*
* Copyright 2003-2008 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
void test_composite_key();

View File

@@ -0,0 +1,18 @@
/* Boost.MultiIndex test for composite_key.
*
* Copyright 2003-2013 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
#include <boost/detail/lightweight_test.hpp>
#include "test_composite_key.hpp"
int main()
{
test_composite_key();
return boost::report_errors();
}

View File

@@ -0,0 +1,75 @@
/* Boost.MultiIndex test for interconvertibilty between const and
* non-const iterators.
*
* Copyright 2003-2013 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
#include "test_conv_iterators.hpp"
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include "pre_multi_index.hpp"
#include "employee.hpp"
#include <boost/detail/lightweight_test.hpp>
using namespace boost::multi_index;
void test_conv_iterators()
{
employee_set es;
es.insert(employee(2,"John",40,7889));
{
const employee_set& ces=es;
employee_set::iterator it=es.find(employee(2,"John",40,7889));
employee_set::const_iterator it1=es.find(employee(2,"John",40,7889));
employee_set::const_iterator it2=ces.find(employee(2,"John",40,7889));
BOOST_TEST(it==it1&&it1==it2&&it2==it);
BOOST_TEST(*it==*it1&&*it1==*it2&&*it2==*it);
}
{
employee_set_by_name& i1=get<1>(es);
const employee_set_by_name& ci1=get<1>(es);
employee_set_by_name::iterator it=i1.find("John");
employee_set_by_name::const_iterator it1=i1.find("John");
employee_set_by_name::const_iterator it2=ci1.find("John");
BOOST_TEST(it==it1&&it1==it2&&it2==it);
BOOST_TEST(*it==*it1&&*it1==*it2&&*it2==*it);
}
{
employee_set_by_name& i1=get<1>(es);
const employee_set_by_name& ci1=get<1>(es);
employee_set_by_name::local_iterator it=i1.begin(i1.bucket("John"));
employee_set_by_name::const_local_iterator it1=i1.begin(i1.bucket("John"));
employee_set_by_name::const_local_iterator it2=ci1.begin(ci1.bucket("John"));
BOOST_TEST(it==it1&&it1==it2&&it2==it);
BOOST_TEST(*it==*it1&&*it1==*it2&&*it2==*it);
}
{
employee_set_as_inserted& i3=get<3>(es);
const employee_set_as_inserted& ci3=get<3>(es);
employee_set_as_inserted::iterator it=i3.begin();
employee_set_as_inserted::const_iterator it1=i3.begin();
employee_set_as_inserted::const_iterator it2=ci3.begin();
BOOST_TEST(it==it1&&it1==it2&&it2==it);
BOOST_TEST(*it==*it1&&*it1==*it2&&*it2==*it);
}
{
employee_set_randomly& i5=get<5>(es);
const employee_set_randomly& ci5=get<5>(es);
employee_set_randomly::iterator it=i5.begin();
employee_set_randomly::const_iterator it1=i5.begin();
employee_set_randomly::const_iterator it2=ci5.begin();
BOOST_TEST(it==it1&&it1==it2&&it2==it);
BOOST_TEST(*it==*it1&&*it1==*it2&&*it2==*it);
}
}

View File

@@ -0,0 +1,12 @@
/* Boost.MultiIndex test for interconvertibilty between const and
* non-const iterators.
*
* Copyright 2003-2008 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
void test_conv_iterators();

View File

@@ -0,0 +1,21 @@
/* Boost.MultiIndex test for interconvertibilty between const and
* non-const iterators.
*
* Copyright 2003-2013 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
#include <boost/detail/lightweight_test.hpp>
#include "test_conv_iterators.hpp"
int main()
{
test_conv_iterators();
return boost::report_errors();
}

View File

@@ -0,0 +1,237 @@
/* Boost.MultiIndex test for copying and assignment.
*
* Copyright 2003-2013 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
#include "test_copy_assignment.hpp"
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <algorithm>
#include <boost/move/utility.hpp>
#include <list>
#include <numeric>
#include <vector>
#include "pre_multi_index.hpp"
#include "employee.hpp"
#include <boost/detail/lightweight_test.hpp>
using namespace boost::multi_index;
#if BOOST_WORKAROUND(__MWERKS__,<=0x3003)
/* The "ISO C++ Template Parser" option makes CW8.3 incorrectly fail at
* expressions of the form sizeof(x) where x is an array local to a
* template function.
*/
#pragma parse_func_templ off
#endif
typedef multi_index_container<int> copyable_and_movable;
struct holder
{
copyable_and_movable c;
};
template<typename Sequence>
static void test_assign()
{
Sequence s;
int a[]={0,1,2,3,4,5};
std::size_t sa=sizeof(a)/sizeof(a[0]);
s.assign(&a[0],&a[sa]);
BOOST_TEST(s.size()==sa&&std::equal(s.begin(),s.end(),&a[0]));
s.assign((const int*)(&a[0]),(const int*)(&a[sa]));
BOOST_TEST(s.size()==sa&&std::equal(s.begin(),s.end(),&a[0]));
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
s.assign({0,1,2,3,4,5});
#else
s.assign(&a[0],&a[sa]);
#endif
BOOST_TEST(s.size()==sa&&std::equal(s.begin(),s.end(),&a[0]));
s.assign((std::size_t)18,37);
BOOST_TEST(s.size()==18&&std::accumulate(s.begin(),s.end(),0)==666);
s.assign((std::size_t)12,167);
BOOST_TEST(s.size()==12&&std::accumulate(s.begin(),s.end(),0)==2004);
}
#if BOOST_WORKAROUND(__MWERKS__,<=0x3003)
#pragma parse_func_templ reset
#endif
template<typename Sequence>
static void test_integral_assign()
{
/* Special cases described in 23.1.1/9: integral types must not
* be taken as iterators in assign(f,l) and insert(p,f,l).
*/
Sequence s;
s.assign(5,10);
BOOST_TEST(s.size()==5&&std::accumulate(s.begin(),s.end(),0)==50);
s.assign(2u,5u);
BOOST_TEST(s.size()==2&&std::accumulate(s.begin(),s.end(),0)==10);
s.clear();
s.insert(s.begin(),5,10);
BOOST_TEST(s.size()==5&&std::accumulate(s.begin(),s.end(),0)==50);
s.insert(s.begin(),2u,5u);
BOOST_TEST(s.size()==7&&std::accumulate(s.begin(),s.end(),0)==60);
}
employee_set produce_employee_set()
{
employee_set es;
es.insert(employee(0,"Petr",60,2837));
es.insert(employee(1,"Jiri",25,2143));
es.insert(employee(2,"Radka",40,4875));
es.insert(employee(3,"Milan",38,3474));
return es;
}
void test_copy_assignment()
{
employee_set es;
employee_set es2(es);
employee_set::allocator_type al=es.get_allocator();
al=get<1>(es).get_allocator();
al=get<2>(es).get_allocator();
al=get<3>(es).get_allocator();
al=get<4>(es).get_allocator();
al=get<5>(es).get_allocator();
BOOST_TEST(es2.empty());
es2.insert(employee(0,"Joe",31,1123));
es2.insert(employee(1,"Robert",27,5601));
es2.insert(employee(2,"John",40,7889));
es2.insert(employee(2,"Aristotle",2388,3357)); /* clash */
es2.insert(employee(3,"Albert",20,9012));
es2.insert(employee(4,"John",57,1002));
es2.insert(employee(0,"Andrew",60,2302)); /* clash */
employee_set es3(es2);
BOOST_TEST(es2==es3);
BOOST_TEST(get<2>(es2)==get<2>(es3));
BOOST_TEST(get<3>(es2)==get<3>(es3));
BOOST_TEST(get<5>(es2)==get<5>(es3));
employee_set es4=employee_set(non_std_allocator<employee>());
employee_set_by_name& i1=get<name>(es4);
i1=get<1>(es2);
BOOST_TEST(es4==es2);
employee_set es5=employee_set(employee_set::ctor_args_list());
employee_set_by_age& i2=get<age>(es5);
i2=get<2>(es2);
BOOST_TEST(i2==get<2>(es2));
employee_set es6;
employee_set_as_inserted& i3=get<as_inserted>(es6);
i3=get<3>(es2);
BOOST_TEST(i3==get<3>(es2));
employee_set es7;
employee_set_randomly& i5=get<randomly>(es7);
i5=get<5>(es2);
BOOST_TEST(i5==get<5>(es2));
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
employee_set es8({{0,"Rose",40,4512},{1,"Mary",38,3345},{2,"Jo",25,7102}});
employee_set es9;
es9={{0,"Rose",40,4512},{1,"Mary",38,3345},{2,"Jo",25,7102},
{0,"Rose",40,4512}};
BOOST_TEST(es8.size()==3);
BOOST_TEST(es9==es8);
es9.clear();
get<0>(es9)={{0,"Rose",40,4512},{1,"Mary",38,3345},{2,"Jo",25,7102},
{0,"Rose",40,4512}};
BOOST_TEST(es9==es8);
es9.clear();
get<0>(es9)={{0,"Rose",40,4512},{2,"Jo",25,7102},{1,"Mary",38,3345}};
BOOST_TEST(es9==es8);
es9.clear();
get<1>(es9)={{1,"Mary",38,3345},{0,"Rose",40,4512},{2,"Jo",25,7102},
{0,"Rose",40,4512}};
BOOST_TEST(es9==es8);
es9.clear();
get<2>(es9)={{2,"Jo",25,7102},{0,"Rose",40,4512},{1,"Mary",38,3345}};
BOOST_TEST(es9==es8);
es9.clear();
get<3>(es9)={{0,"Rose",40,4512},{1,"Mary",38,3345},{1,"Mary",38,3345},
{2,"Jo",25,7102}};
BOOST_TEST(es9==es8);
es9.clear();
get<4>(es9)={{1,"Mary",38,3345},{2,"Jo",25,7102},{0,"Rose",40,4512}};
BOOST_TEST(es9==es8);
es9.clear();
get<5>(es9)={{1,"Mary",38,3345},{2,"Jo",25,7102},{0,"Rose",40,4512},
{2,"Jo",25,7102}};
BOOST_TEST(es9==es8);
#endif
employee_set es10(produce_employee_set()),es11(produce_employee_set());
BOOST_TEST(es10==es11);
employee_set es12(boost::move(es10));
BOOST_TEST(es10.empty());
BOOST_TEST(es11==es12);
es10=boost::move(es12);
BOOST_TEST(es12.empty());
BOOST_TEST(es11==es10);
std::list<employee> l;
l.push_back(employee(3,"Anna",31,5388));
l.push_back(employee(1,"Rachel",27,9012));
l.push_back(employee(2,"Agatha",40,1520));
employee_set es13(l.begin(),l.end());
l.sort();
BOOST_TEST(es13.size()==l.size()&&
std::equal(es13.begin(),es13.end(),l.begin()));
test_assign<multi_index_container<int,indexed_by<sequenced<> > > >();
test_integral_assign<
multi_index_container<int,indexed_by<sequenced<> > > >();
test_assign<multi_index_container<int,indexed_by<random_access<> > > >();
test_integral_assign<
multi_index_container<int,indexed_by<random_access<> > > >();
/* Testcase for problem described at http://www.boost.org/doc/html/move/
* emulation_limitations.html#move.emulation_limitations.assignment_operator
*/
holder h((holder()));
h=holder();
}

View File

@@ -0,0 +1,11 @@
/* Boost.MultiIndex test for copying and assignment.
*
* Copyright 2003-2008 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
void test_copy_assignment();

View File

@@ -0,0 +1,18 @@
/* Boost.MultiIndex test for copying and assignment.
*
* Copyright 2003-2013 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
#include <boost/detail/lightweight_test.hpp>
#include "test_copy_assignment.hpp"
int main()
{
test_copy_assignment();
return boost::report_errors();
}

View File

@@ -0,0 +1,118 @@
/* Boost.MultiIndex test for standard hash operations.
*
* Copyright 2003-2013 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
#include "test_hash_ops.hpp"
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <iterator>
#include <boost/detail/lightweight_test.hpp>
#include "pre_multi_index.hpp"
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/identity.hpp>
#include <vector>
#include <iostream>
using namespace boost::multi_index;
template<typename HashedContainer>
void check_load_factor(const HashedContainer& hc)
{
float lf=(float)hc.size()/hc.bucket_count();
BOOST_TEST(lf<=hc.load_factor()+1.E-6);
BOOST_TEST(lf>=hc.load_factor()-1.E-6);
BOOST_TEST(lf<=hc.max_load_factor()+1.E-6);
}
typedef multi_index_container<
int,
indexed_by<
hashed_unique<identity<int> >
>
> hash_container;
void test_hash_ops()
{
hash_container hc;
BOOST_TEST(hc.max_load_factor()==1.0f);
BOOST_TEST(hc.bucket_count()<=hc.max_bucket_count());
hc.insert(1000);
hash_container::size_type buc=hc.bucket(1000);
hash_container::local_iterator it0=hc.begin(buc);
hash_container::local_iterator it1=hc.end(buc);
BOOST_TEST(
(hash_container::size_type)std::distance(it0,it1)==hc.bucket_size(buc)&&
hc.bucket_size(buc)==1&&*it0==1000);
hc.clear();
for(hash_container::size_type s=2*hc.bucket_count();s--;){
hc.insert((int)s);
}
check_load_factor(hc);
hc.max_load_factor(0.5f);
BOOST_TEST(hc.max_load_factor()==0.5f);
hc.insert(-1);
check_load_factor(hc);
hc.rehash(1);
BOOST_TEST(hc.bucket_count()>=1);
check_load_factor(hc);
hc.max_load_factor(0.25f);
hc.rehash(1);
BOOST_TEST(hc.bucket_count()>=1);
check_load_factor(hc);
hash_container::size_type bc=4*hc.bucket_count();
hc.max_load_factor(0.125f);
hc.rehash(bc);
BOOST_TEST(hc.bucket_count()>=bc);
check_load_factor(hc);
bc=2*hc.bucket_count();
hc.rehash(bc);
BOOST_TEST(hc.bucket_count()>=bc);
check_load_factor(hc);
hc.clear();
hc.insert(0);
hc.rehash(1);
BOOST_TEST(hc.bucket_count()>=1);
check_load_factor(hc);
hash_container hc2;
hc2.insert(0);
hc2.max_load_factor(0.5f/hc2.bucket_count());
BOOST_TEST(hc2.load_factor()>hc2.max_load_factor());
hc2.reserve(1);
BOOST_TEST(hc2.load_factor()<hc2.max_load_factor());
hash_container hc3;
hc3.clear();
hc3.max_load_factor(1.0f);
hc3.reserve(1000);
hash_container::size_type bc3=hc3.bucket_count();
BOOST_TEST(bc3>=1000);
std::vector<int> v;
for(unsigned int n=0;n<bc3;++n)v.push_back(n);
hc3.insert(v.begin(),v.end());
BOOST_TEST(hc3.bucket_count()==bc3); /* LWG issue 2156 */
hc3.max_load_factor(0.25f);
hc3.reserve(100);
BOOST_TEST(hc3.bucket_count()>bc3);
bc3=hc3.bucket_count();
hc3.reserve((hash_container::size_type)(3.0f*hc3.max_load_factor()*bc3));
BOOST_TEST(hc3.bucket_count()>bc3);
}

View File

@@ -0,0 +1,11 @@
/* Boost.MultiIndex test for standard hash operations.
*
* Copyright 2003-2008 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
void test_hash_ops();

View File

@@ -0,0 +1,18 @@
/* Boost.MultiIndex test for standard hash operations.
*
* Copyright 2003-2013 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
#include <boost/detail/lightweight_test.hpp>
#include "test_hash_ops.hpp"
int main()
{
test_hash_ops();
return boost::report_errors();
}

View File

@@ -0,0 +1,250 @@
/* Boost.MultiIndex test for iterators.
*
* Copyright 2003-2013 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
#include "test_iterators.hpp"
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include "pre_multi_index.hpp"
#include "employee.hpp"
#include <boost/detail/lightweight_test.hpp>
#include <boost/next_prior.hpp>
using namespace boost::multi_index;
template<typename Index>
void test_non_const_iterators(Index& i,int target)
{
typedef typename Index::iterator iterator;
typedef typename Index::reverse_iterator reverse_iterator;
int n=0;
for(iterator it=i.begin();it!=i.end();++it){
BOOST_TEST(i.iterator_to(*it)==it);
n+=it->id;
}
int m=0;
for(reverse_iterator rit=i.rbegin();rit!=i.rend();++rit){
m+=rit->id;
}
int p=0;
for(iterator it2=i.end();it2!=i.begin();){
--it2;
p+=it2->id;
}
int q=0;
for(reverse_iterator rit2=i.rend();rit2!=i.rbegin();){
--rit2;
q+=rit2->id;
}
BOOST_TEST(n==target&&n==m&&n==p&&n==q);
}
template<typename Index>
void test_const_iterators(const Index& i,int target)
{
typedef typename Index::const_iterator const_iterator;
typedef typename Index::const_reverse_iterator const_reverse_iterator;
BOOST_TEST(i.cbegin()==i.begin());
BOOST_TEST(i.cend()==i.end());
BOOST_TEST(i.crbegin()==i.rbegin());
BOOST_TEST(i.crend()==i.rend());
int n=0;
for(const_iterator it=i.begin();it!=i.end();++it){
BOOST_TEST(i.iterator_to(*it)==it);
n+=it->id;
}
int m=0;
for(const_reverse_iterator rit=i.rbegin();rit!=i.rend();++rit){
m+=rit->id;
}
int p=0;
for(const_iterator it2=i.end();it2!=i.begin();){
--it2;
p+=it2->id;
}
int q=0;
for(const_reverse_iterator rit2=i.rend();rit2!=i.rbegin();){
--rit2;
q+=rit2->id;
}
BOOST_TEST(n==target&&n==m&&n==p&&n==q);
}
template<typename Index>
void test_non_const_hashed_iterators(Index& i,int target)
{
typedef typename Index::iterator iterator;
typedef typename Index::local_iterator local_iterator;
typedef typename Index::size_type size_type;
int n=0;
for(iterator it=i.begin();it!=i.end();++it){
BOOST_TEST(i.iterator_to(*it)==it);
n+=it->id;
}
int m=0;
for(size_type buc=0;buc<i.bucket_count();++buc){
for(local_iterator it=i.begin(buc);it!=i.end(buc);++it){
BOOST_TEST(i.local_iterator_to(*it)==it);
m+=it->id;
}
}
BOOST_TEST(n==target&&n==m);
}
template<typename Index>
void test_const_hashed_iterators(const Index& i,int target)
{
typedef typename Index::const_iterator const_iterator;
typedef typename Index::const_local_iterator const_local_iterator;
typedef typename Index::size_type size_type;
BOOST_TEST(i.cbegin()==i.begin());
BOOST_TEST(i.cend()==i.end());
int n=0;
for(const_iterator it=i.begin();it!=i.end();++it){
BOOST_TEST(i.iterator_to(*it)==it);
n+=it->id;
}
int m=0;
for(size_type buc=0;buc<i.bucket_count();++buc){
BOOST_TEST(i.cbegin(buc)==i.begin(buc));
BOOST_TEST(i.cend(buc)==i.end(buc));
for(const_local_iterator it=i.begin(buc);it!=i.end(buc);++it){
BOOST_TEST(i.local_iterator_to(*it)==it);
m+=it->id;
}
}
BOOST_TEST(n==target&&n==m);
}
template<typename Index>
void test_non_const_rnd_iterators(Index& i,int target)
{
typedef typename Index::iterator iterator;
typedef typename Index::reverse_iterator reverse_iterator;
typedef typename Index::difference_type difference_type;
iterator middle=i.begin()+(i.end()-i.begin())/2;
difference_type off=middle-i.begin();
reverse_iterator rmiddle=i.rbegin()+off;
bool odd=((i.end()-i.begin())%2)!=0;
int n=0;
for(iterator it=i.begin();it!=middle;++it){
BOOST_TEST(i.iterator_to(*it)==it);
n+=it->id;
n+=it[off].id;
}
if(odd)n+=(boost::prior(i.end()))->id;
int m=0;
for(reverse_iterator rit=i.rbegin();rit!=rmiddle;++rit){
m+=rit->id;
m+=(rit+off)->id;
}
if(odd)m+=(boost::prior(i.rend()))->id;
int p=0;
for(iterator it2=i.end();it2!=middle;){
--it2;
p+=it2->id;
p+=(it2-off)->id;
}
if(odd)p-=middle->id;
int q=0;
for(reverse_iterator rit2=i.rend();rit2!=rmiddle;){
--rit2;
q+=rit2->id;
q+=(rit2-off)->id;
}
if(odd)q-=rmiddle->id;
BOOST_TEST(n==target&&n==m&&n==p&&n==q);
}
template<typename Index>
void test_const_rnd_iterators(const Index& i,int target)
{
typedef typename Index::const_iterator const_iterator;
typedef typename Index::const_reverse_iterator const_reverse_iterator;
typedef typename Index::difference_type difference_type;
BOOST_TEST(i.cbegin()==i.begin());
BOOST_TEST(i.cend()==i.end());
BOOST_TEST(i.crbegin()==i.rbegin());
BOOST_TEST(i.crend()==i.rend());
const_iterator middle=i.begin()+(i.end()-i.begin())/2;
difference_type off=middle-i.begin();
const_reverse_iterator rmiddle=i.rbegin()+off;
bool odd=((i.end()-i.begin())%2)!=0;
int n=0;
for(const_iterator it=i.begin();it!=middle;++it){
BOOST_TEST(i.iterator_to(*it)==it);
n+=it->id;
n+=it[off].id;
}
if(odd)n+=(boost::prior(i.end()))->id;
int m=0;
for(const_reverse_iterator rit=i.rbegin();rit!=rmiddle;++rit){
m+=rit->id;
m+=(rit+off)->id;
}
if(odd)m+=(boost::prior(i.rend()))->id;
int p=0;
for(const_iterator it2=i.end();it2!=middle;){
--it2;
p+=it2->id;
p+=(it2-off)->id;
}
if(odd)p-=middle->id;
int q=0;
for(const_reverse_iterator rit2=i.rend();rit2!=rmiddle;){
--rit2;
q+=rit2->id;
q+=(rit2-off)->id;
}
if(odd)q-=rmiddle->id;
BOOST_TEST(n==target&&n==m&&n==p&&n==q);
}
void test_iterators()
{
employee_set es;
es.insert(employee(0,"Joe",31,1123));
es.insert(employee(1,"Robert",27,5601));
es.insert(employee(2,"John",40,7889));
es.insert(employee(3,"Albert",20,9012));
es.insert(employee(4,"John",57,1002));
int target=0+1+2+3+4;
test_non_const_iterators (es,target);
test_const_iterators (es,target);
test_non_const_hashed_iterators(get<1>(es),target);
test_const_hashed_iterators (get<1>(es),target);
test_non_const_iterators (get<2>(es),target);
test_const_iterators (get<2>(es),target);
test_non_const_iterators (get<3>(es),target);
test_const_iterators (get<3>(es),target);
test_non_const_hashed_iterators(get<4>(es),target);
test_const_hashed_iterators (get<4>(es),target);
test_non_const_rnd_iterators (get<5>(es),target);
test_const_rnd_iterators (get<5>(es),target);
}

View File

@@ -0,0 +1,11 @@
/* Boost.MultiIndex test for iterators.
*
* Copyright 2003-2008 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
void test_iterators();

View File

@@ -0,0 +1,19 @@
/* Boost.MultiIndex test for iterators.
*
* Copyright 2003-2013 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
#include <boost/detail/lightweight_test.hpp>
#include "test_iterators.hpp"
int main()
{
test_iterators();
return boost::report_errors();
}

View File

@@ -0,0 +1,471 @@
/* Boost.MultiIndex test for key extractors.
*
* Copyright 2003-2015 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
#include "test_key_extractors.hpp"
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <boost/detail/lightweight_test.hpp>
#include "pre_multi_index.hpp"
#include <boost/multi_index/key_extractors.hpp>
#include <boost/ref.hpp>
#include <boost/scoped_ptr.hpp>
#include <list>
using namespace boost::multi_index;
using namespace boost::tuples;
struct test_class
{
int int_member;
const int int_cmember;
bool bool_mem_fun_const()const{return true;}
bool bool_mem_fun(){return false;}
static bool bool_global_fun(test_class){return true;}
static bool bool_global_fun_const_ref(const test_class&){return false;}
static bool bool_global_fun_ref(test_class&){return true;}
test_class(int i=0):int_member(i),int_cmember(i){}
test_class(int i,int j):int_member(i),int_cmember(j){}
test_class& operator=(const test_class& x)
{
int_member=x.int_member;
return *this;
}
bool operator<(const test_class& x)const
{
if(int_member<x.int_member)return true;
if(x.int_member<int_member)return false;
return int_cmember<x.int_cmember;
}
bool operator==(const test_class& x)const
{
return int_member==x.int_member&&int_cmember==x.int_cmember;
}
};
struct test_derived_class:test_class
{
test_derived_class(int i=0):test_class(i){}
test_derived_class(int i,int j):test_class(i,j){}
};
typedef identity<test_class> idn;
typedef identity<const test_class> cidn;
typedef BOOST_MULTI_INDEX_MEMBER(test_class,int,int_member) key_m;
typedef BOOST_MULTI_INDEX_MEMBER(test_class,const int,int_member) ckey_m;
typedef BOOST_MULTI_INDEX_MEMBER(test_class,const int,int_cmember) key_cm;
typedef BOOST_MULTI_INDEX_CONST_MEM_FUN(
test_class,bool,bool_mem_fun_const) key_cmf;
typedef BOOST_MULTI_INDEX_MEM_FUN(test_class,bool,bool_mem_fun) key_mf;
typedef global_fun<test_class,bool,&test_class::bool_global_fun> key_gf;
typedef global_fun<
const test_class&,bool,
&test_class::bool_global_fun_const_ref
> key_gcrf;
typedef global_fun<
test_class&,bool,
&test_class::bool_global_fun_ref
> key_grf;
typedef composite_key<
test_class,
idn,
key_m,
key_cm,
key_cmf
> compkey;
typedef composite_key<
test_class,
cidn,
ckey_m
> ccompkey;
typedef composite_key<
boost::reference_wrapper<test_class>,
key_mf
> ccompw_key;
#if !defined(BOOST_NO_SFINAE)
/* testcases for problems with non-copyable classes reported at
* http://lists.boost.org/Archives/boost/2006/04/103065.php
*/
struct test_nc_class
{
int int_member;
const int int_cmember;
bool bool_mem_fun_const()const{return true;}
bool bool_mem_fun(){return false;}
static bool bool_global_fun_const_ref(const test_nc_class&){return false;}
static bool bool_global_fun_ref(test_nc_class&){return true;}
test_nc_class(int i=0):int_member(i),int_cmember(i){}
test_nc_class(int i,int j):int_member(i),int_cmember(j){}
bool operator==(const test_nc_class& x)const
{
return int_member==x.int_member&&int_cmember==x.int_cmember;
}
private:
test_nc_class(const test_nc_class&);
test_nc_class& operator=(const test_nc_class&);
};
struct test_nc_derived_class:test_nc_class
{
test_nc_derived_class(int i=0):test_nc_class(i){}
test_nc_derived_class(int i,int j):test_nc_class(i,j){}
};
typedef identity<test_nc_class> nc_idn;
typedef identity<const test_nc_class> nc_cidn;
typedef BOOST_MULTI_INDEX_MEMBER(test_nc_class,int,int_member) nc_key_m;
typedef BOOST_MULTI_INDEX_MEMBER(
test_nc_class,const int,int_member) nc_ckey_m;
typedef BOOST_MULTI_INDEX_CONST_MEM_FUN(
test_nc_class,bool,bool_mem_fun_const) nc_key_cmf;
typedef BOOST_MULTI_INDEX_MEM_FUN(
test_nc_class,bool,bool_mem_fun) nc_key_mf;
typedef global_fun<
const test_nc_class&,bool,
&test_nc_class::bool_global_fun_const_ref
> nc_key_gcrf;
typedef global_fun<
test_nc_class&,bool,
&test_nc_class::bool_global_fun_ref
> nc_key_grf;
typedef composite_key<
test_nc_class,
nc_idn,
nc_key_m,
nc_ckey_m,
nc_key_cmf
> nc_compkey;
#endif
void test_key_extractors()
{
idn id;
cidn cid;
key_m k_m;
ckey_m ck_m;
key_cm k_cm;
key_cmf k_cmf;
key_mf k_mf;
key_gf k_gf;
key_gcrf k_gcrf;
key_grf k_grf;
compkey cmpk;
ccompkey ccmpk;
ccompw_key ccmpk_w;
test_derived_class td(-1,0);
const test_derived_class& ctdr=td;
test_class& tr=td;
const test_class& ctr=tr;
test_derived_class* tdp=&td;
const test_derived_class* ctdp=&ctdr;
test_class* tp=&tr;
const test_class* ctp=&tr;
test_class** tpp=&tp;
const test_class** ctpp=&ctp;
boost::scoped_ptr<test_class*> tap(new test_class*(tp));
boost::scoped_ptr<const test_class*> ctap(new const test_class*(ctp));
boost::reference_wrapper<test_class> tw(tr);
boost::reference_wrapper<const test_class> ctw(tr);
id(tr).int_member=0;
BOOST_TEST(id(tr).int_member==0);
BOOST_TEST(cid(tr).int_member==0);
BOOST_TEST(k_m(tr)==0);
BOOST_TEST(ck_m(tr)==0);
BOOST_TEST(cmpk(tr)==make_tuple(test_class(0,0),0,0,true));
BOOST_TEST(ccmpk(tr)==make_tuple(test_class(0,0),0));
BOOST_TEST(id(ctr).int_member==0);
BOOST_TEST(cid(ctr).int_member==0);
BOOST_TEST(k_m(ctr)==0);
BOOST_TEST(ck_m(ctr)==0);
BOOST_TEST(cmpk(ctr)==make_tuple(test_class(0,0),0,0,true));
BOOST_TEST(ccmpk(ctr)==make_tuple(test_class(0,0),0));
#if !defined(BOOST_NO_SFINAE)
BOOST_TEST(id(td).int_member==0);
BOOST_TEST(cid(td).int_member==0);
BOOST_TEST(k_m(td)==0);
BOOST_TEST(ck_m(td)==0);
BOOST_TEST(cmpk(td)==make_tuple(test_class(0,0),0,0,true));
BOOST_TEST(ccmpk(td)==make_tuple(test_class(0,0),0));
BOOST_TEST(id(ctdr).int_member==0);
BOOST_TEST(cid(ctdr).int_member==0);
BOOST_TEST(k_m(ctdr)==0);
BOOST_TEST(ck_m(ctdr)==0);
BOOST_TEST(cmpk(ctdr)==make_tuple(test_class(0,0),0,0,true));
BOOST_TEST(ccmpk(ctdr)==make_tuple(test_class(0,0),0));
#endif
k_m(tr)=1;
BOOST_TEST(id(tp).int_member==1);
BOOST_TEST(cid(tp).int_member==1);
BOOST_TEST(k_m(tp)==1);
BOOST_TEST(ck_m(tp)==1);
BOOST_TEST(cmpk(tp)==make_tuple(test_class(1,0),1,0,true));
BOOST_TEST(ccmpk(tp)==make_tuple(test_class(1,0),1));
BOOST_TEST(cid(ctp).int_member==1);
BOOST_TEST(ck_m(ctp)==1);
BOOST_TEST(cmpk(ctp)==make_tuple(test_class(1,0),1,0,true));
BOOST_TEST(ccmpk(ctp)==make_tuple(test_class(1,0),1));
#if !defined(BOOST_NO_SFINAE)
BOOST_TEST(id(tdp).int_member==1);
BOOST_TEST(cid(tdp).int_member==1);
BOOST_TEST(k_m(tdp)==1);
BOOST_TEST(ck_m(tdp)==1);
BOOST_TEST(cmpk(tdp)==make_tuple(test_class(1,0),1,0,true));
BOOST_TEST(ccmpk(tdp)==make_tuple(test_class(1,0),1));
BOOST_TEST(cid(ctdp).int_member==1);
BOOST_TEST(ck_m(ctdp)==1);
BOOST_TEST(cmpk(ctdp)==make_tuple(test_class(1,0),1,0,true));
BOOST_TEST(ccmpk(ctdp)==make_tuple(test_class(1,0),1));
#endif
k_m(tp)=2;
BOOST_TEST(id(tpp).int_member==2);
BOOST_TEST(cid(tpp).int_member==2);
BOOST_TEST(k_m(tpp)==2);
BOOST_TEST(ck_m(tpp)==2);
BOOST_TEST(cmpk(tpp)==make_tuple(test_class(2,0),2,0,true));
BOOST_TEST(ccmpk(tpp)==make_tuple(test_class(2,0),2));
BOOST_TEST(cid(ctpp).int_member==2);
BOOST_TEST(ck_m(ctpp)==2);
BOOST_TEST(cmpk(ctpp)==make_tuple(test_class(2,0),2,0,true));
BOOST_TEST(ccmpk(ctpp)==make_tuple(test_class(2,0),2));
k_m(tpp)=3;
BOOST_TEST(id(tap).int_member==3);
BOOST_TEST(cid(tap).int_member==3);
BOOST_TEST(k_m(tap)==3);
BOOST_TEST(ck_m(tap)==3);
BOOST_TEST(cmpk(tap)==make_tuple(test_class(3,0),3,0,true));
BOOST_TEST(ccmpk(tap)==make_tuple(test_class(3,0),3));
BOOST_TEST(cid(ctap).int_member==3);
BOOST_TEST(ck_m(ctap)==3);
BOOST_TEST(cmpk(ctap)==make_tuple(test_class(3,0),3,0,true));
BOOST_TEST(ccmpk(ctap)==make_tuple(test_class(3,0),3));
k_m(tap)=4;
BOOST_TEST(id(tw).int_member==4);
BOOST_TEST(cid(tw).int_member==4);
BOOST_TEST(k_m(tw)==4);
BOOST_TEST(ck_m(tw)==4);
BOOST_TEST(cmpk(tw)==make_tuple(test_class(4,0),4,0,true));
BOOST_TEST(ccmpk(tw)==make_tuple(test_class(4,0),4));
k_m(tw)=5;
BOOST_TEST(id(ctw).int_member==5);
BOOST_TEST(cid(ctw).int_member==5);
BOOST_TEST(k_m(ctw)==5);
BOOST_TEST(ck_m(ctw)==5);
BOOST_TEST(cmpk(ctw)==make_tuple(test_class(5,0),5,0,true));
BOOST_TEST(ccmpk(ctw)==make_tuple(test_class(5,0),5));
BOOST_TEST(k_cm(tr)==0);
BOOST_TEST(k_cm(ctr)==0);
#if !defined(BOOST_NO_SFINAE)
BOOST_TEST(k_cm(td)==0);
BOOST_TEST(k_cm(ctdr)==0);
#endif
BOOST_TEST(k_cm(tp)==0);
BOOST_TEST(k_cm(ctp)==0);
#if !defined(BOOST_NO_SFINAE)
BOOST_TEST(k_cm(tdp)==0);
BOOST_TEST(k_cm(ctdp)==0);
#endif
BOOST_TEST(k_cm(tpp)==0);
BOOST_TEST(k_cm(ctpp)==0);
BOOST_TEST(k_cm(tap)==0);
BOOST_TEST(k_cm(ctap)==0);
BOOST_TEST(k_cm(tw)==0);
BOOST_TEST(k_cm(ctw)==0);
BOOST_TEST(k_cmf(tr));
BOOST_TEST(k_cmf(ctr));
#if !defined(BOOST_NO_SFINAE)
BOOST_TEST(k_cmf(td));
BOOST_TEST(k_cmf(ctdr));
#endif
BOOST_TEST(k_cmf(tp));
BOOST_TEST(k_cmf(ctp));
#if !defined(BOOST_NO_SFINAE)
BOOST_TEST(k_cmf(tdp));
BOOST_TEST(k_cmf(ctdp));
#endif
BOOST_TEST(k_cmf(tpp));
BOOST_TEST(k_cmf(ctpp));
BOOST_TEST(k_cmf(tap));
BOOST_TEST(k_cmf(ctap));
BOOST_TEST(k_cmf(tw));
BOOST_TEST(k_cmf(ctw));
BOOST_TEST(!k_mf(tr));
#if !defined(BOOST_NO_SFINAE)
BOOST_TEST(!k_mf(td));
#endif
BOOST_TEST(!k_mf(tp));
#if !defined(BOOST_NO_SFINAE)
BOOST_TEST(!k_mf(tdp));
#endif
BOOST_TEST(!k_mf(tpp));
BOOST_TEST(!k_mf(tap));
BOOST_TEST(!k_mf(tw));
BOOST_TEST(k_gf(tr));
BOOST_TEST(k_gf(ctr));
#if !defined(BOOST_NO_SFINAE)
BOOST_TEST(k_gf(td));
BOOST_TEST(k_gf(ctdr));
#endif
BOOST_TEST(k_gf(tp));
BOOST_TEST(k_gf(ctp));
#if !defined(BOOST_NO_SFINAE)
BOOST_TEST(k_gf(tdp));
BOOST_TEST(k_gf(ctdp));
#endif
BOOST_TEST(k_gf(tpp));
BOOST_TEST(k_gf(ctpp));
BOOST_TEST(k_gf(tap));
BOOST_TEST(k_gf(ctap));
BOOST_TEST(k_gf(tw));
BOOST_TEST(k_gf(ctw));
BOOST_TEST(!k_gcrf(tr));
BOOST_TEST(!k_gcrf(ctr));
#if !defined(BOOST_NO_SFINAE)
BOOST_TEST(!k_gcrf(td));
BOOST_TEST(!k_gcrf(ctdr));
#endif
BOOST_TEST(!k_gcrf(tp));
BOOST_TEST(!k_gcrf(ctp));
#if !defined(BOOST_NO_SFINAE)
BOOST_TEST(!k_gcrf(tdp));
BOOST_TEST(!k_gcrf(ctdp));
#endif
BOOST_TEST(!k_gcrf(tpp));
BOOST_TEST(!k_gcrf(ctpp));
BOOST_TEST(!k_gcrf(tap));
BOOST_TEST(!k_gcrf(ctap));
BOOST_TEST(!k_gcrf(tw));
BOOST_TEST(!k_gcrf(ctw));
BOOST_TEST(k_grf(tr));
#if !defined(BOOST_NO_SFINAE)
BOOST_TEST(k_grf(td));
#endif
BOOST_TEST(k_grf(tp));
#if !defined(BOOST_NO_SFINAE)
BOOST_TEST(k_grf(tdp));
#endif
BOOST_TEST(k_grf(tpp));
BOOST_TEST(k_grf(tap));
BOOST_TEST(k_grf(tw));
BOOST_TEST(ccmpk_w(tw)==make_tuple(false));
#if !defined(BOOST_NO_SFINAE)
/* testcases for problems with non-copyable classes reported at
* http://lists.boost.org/Archives/boost/2006/04/103065.php
*/
nc_idn nc_id;
nc_cidn nc_cid;
nc_key_m nc_k_m;
nc_ckey_m nc_ck_m;
nc_key_cmf nc_k_cmf;
nc_key_mf nc_k_mf;
nc_key_gcrf nc_k_gcrf;
nc_key_grf nc_k_grf;
nc_compkey nc_cmpk;
test_nc_derived_class nc_td(-1,0);
nc_id(nc_td).int_member=0;
BOOST_TEST(nc_id(nc_td).int_member==0);
BOOST_TEST(nc_cid(nc_td).int_member==0);
nc_k_m(&nc_td)=1;
BOOST_TEST(nc_k_m(&nc_td)==1);
BOOST_TEST(nc_ck_m(&nc_td)==1);
BOOST_TEST(nc_k_cmf(nc_td));
BOOST_TEST(!nc_k_mf(nc_td));
BOOST_TEST(!nc_k_gcrf(nc_td));
BOOST_TEST(nc_k_grf(nc_td));
test_nc_class nc_t(1,0);
BOOST_TEST(nc_cmpk(nc_td)==make_tuple(boost::cref(nc_t),1,1,true));
#endif
std::list<test_class> tl;
for(int i=0;i<20;++i)tl.push_back(test_class(i));
int j=0;
for(std::list<test_class>::iterator it=tl.begin();it!=tl.end();++it){
BOOST_TEST(k_m(it)==j);
BOOST_TEST(k_cm(it)==j);
BOOST_TEST(k_cmf(it));
BOOST_TEST(!k_mf(it));
BOOST_TEST(k_gf(it));
BOOST_TEST(!k_gcrf(it));
BOOST_TEST(k_grf(it));
BOOST_TEST(cmpk(it)==make_tuple(test_class(j),j,j,true));
BOOST_TEST(ccmpk(it)==make_tuple(test_class(j),j));
++j;
}
}

View File

@@ -0,0 +1,11 @@
/* Boost.MultiIndex test for key extractors.
*
* Copyright 2003-2008 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
void test_key_extractors();

View File

@@ -0,0 +1,18 @@
/* Boost.MultiIndex test for key extractors.
*
* Copyright 2003-2013 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
#include <boost/detail/lightweight_test.hpp>
#include "test_key_extractors.hpp"
int main()
{
test_key_extractors();
return boost::report_errors();
}

View File

@@ -0,0 +1,275 @@
/* Boost.MultiIndex test for standard list operations.
*
* Copyright 2003-2013 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
#include "test_list_ops.hpp"
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <algorithm>
#include <vector>
#include <boost/detail/lightweight_test.hpp>
#include "pre_multi_index.hpp"
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/multi_index/random_access_index.hpp>
#include <boost/preprocessor/seq/enum.hpp>
using namespace boost::multi_index;
#undef CHECK_EQUAL
#define CHECK_EQUAL(p,check_seq) \
{\
int v[]={BOOST_PP_SEQ_ENUM(check_seq)};\
std::size_t size_v=sizeof(v)/sizeof(int);\
BOOST_TEST(std::size_t(std::distance((p).begin(),(p).end()))==size_v);\
BOOST_TEST(std::equal((p).begin(),(p).end(),&v[0]));\
}
#undef CHECK_VOID_RANGE
#define CHECK_VOID_RANGE(p) BOOST_TEST((p).first==(p).second)
struct is_even
{
bool operator()(int x)const{return x%2==0;}
};
template <int m>
struct same_integral_div
{
bool operator()(int x,int y)const{return (x/m)==(y/m);}
};
template <typename Container,typename Compare>
bool is_sorted(
const Container& c,const Compare& comp=Compare())
{
if(c.empty())return true;
typedef typename Container::const_iterator const_iterator;
for(const_iterator it(c.begin());;){
const_iterator it2=it;
++it2;
if(it2==c.end())return true;
if(comp(*it2,*it))return false;
it=it2;
}
}
#if BOOST_WORKAROUND(__MWERKS__,<=0x3003)
/* The "ISO C++ Template Parser" option makes CW8.3 incorrectly fail at
* expressions of the form sizeof(x) where x is an array local to a
* template function.
*/
#pragma parse_func_templ off
#endif
template<typename Sequence>
static void test_list_ops_unique_seq()
{
typedef typename nth_index<Sequence,1>::type sequenced_index;
Sequence ss,ss2;
sequenced_index &si=get<1>(ss),&si2=get<1>(ss2);
si.push_front(0); /* 0 */
si.push_front(4); /* 40 */
ss.insert(2); /* 402 */
ss.insert(5); /* 4025 */
si.push_front(3); /* 34025 */
si.push_back(6); /* 340256 */
si.push_back(1); /* 3402561 */
si.insert(project<1>(ss,ss.find(2)),8); /* 34082561 */
si2=si;
CHECK_EQUAL(si,(3)(4)(0)(8)(2)(5)(6)(1));
si.remove(8);
CHECK_EQUAL(si,(3)(4)(0)(2)(5)(6)(1));
si.remove_if(is_even());
CHECK_EQUAL(si,(3)(5)(1));
si.splice(si.end(),si2);
CHECK_EQUAL(si,(3)(5)(1)(4)(0)(8)(2)(6));
CHECK_EQUAL(si2,(3)(5)(1));
si.splice(project<1>(ss,ss.find(4)),si,project<1>(ss,ss.find(8)));
CHECK_EQUAL(si,(3)(5)(1)(8)(4)(0)(2)(6));
si2.clear();
si2.splice(si2.begin(),si,si.begin());
si.splice(si.end(),si2,si2.begin());
CHECK_EQUAL(si,(5)(1)(8)(4)(0)(2)(6)(3));
BOOST_TEST(si2.empty());
si2.splice(si2.end(),si,project<1>(ss,ss.find(0)),project<1>(ss,ss.find(6)));
CHECK_EQUAL(si,(5)(1)(8)(4)(6)(3));
CHECK_EQUAL(si2,(0)(2));
si.splice(si.begin(),si,si.begin(),si.begin());
CHECK_EQUAL(si,(5)(1)(8)(4)(6)(3));
si.splice(project<1>(ss,ss.find(8)),si,project<1>(ss,ss.find(4)),si.end());
CHECK_EQUAL(si,(5)(1)(4)(6)(3)(8));
si.sort();
si2.sort();
BOOST_TEST(is_sorted(si,std::less<int>()));
BOOST_TEST(is_sorted(si2,std::less<int>()));
si.merge(si2);
BOOST_TEST(is_sorted(si,std::less<int>()));
BOOST_TEST(si2.empty());
{
Sequence ss3(ss);
sequenced_index &si3=get<1>(ss3);
si3.sort(std::greater<int>());
si.reverse();
BOOST_TEST(si==si3);
}
si2.splice(si2.end(),si,project<1>(ss,ss.find(6)),project<1>(ss,ss.find(3)));
CHECK_EQUAL(si2,(6)(5)(4));
si.merge(si2,std::greater<int>());
BOOST_TEST(is_sorted(si,std::greater<int>()));
BOOST_TEST(si2.empty());
/* testcase for bug reported at
* https://svn.boost.org/trac/boost/ticket/3076
*/
{
Sequence ss3;
sequenced_index &si3=get<1>(ss3);
si3.sort();
}
}
template<typename Sequence>
static void test_list_ops_non_unique_seq()
{
typedef typename Sequence::iterator iterator;
Sequence ss;
for(int i=0;i<10;++i){
ss.push_back(i);
ss.push_back(i);
ss.push_front(i);
ss.push_front(i);
} /* 9988776655443322110000112233445566778899 */
ss.unique();
CHECK_EQUAL(
ss,
(9)(8)(7)(6)(5)(4)(3)(2)(1)(0)
(1)(2)(3)(4)(5)(6)(7)(8)(9));
iterator it=ss.begin();
for(int j=0;j<9;++j,++it){} /* it points to o */
Sequence ss2;
ss2.splice(ss2.end(),ss,ss.begin(),it);
ss2.reverse();
ss.merge(ss2);
CHECK_EQUAL(
ss,
(0)(1)(1)(2)(2)(3)(3)(4)(4)(5)(5)
(6)(6)(7)(7)(8)(8)(9)(9));
ss.unique(same_integral_div<3>());
CHECK_EQUAL(ss,(0)(3)(6)(9));
ss.unique(same_integral_div<1>());
CHECK_EQUAL(ss,(0)(3)(6)(9));
/* testcases for bugs reported at
* http://lists.boost.org/boost-users/2006/09/22604.php
*/
{
Sequence ss_,ss2_;
ss_.push_back(0);
ss2_.push_back(0);
ss_.splice(ss_.end(),ss2_,ss2_.begin());
CHECK_EQUAL(ss_,(0)(0));
BOOST_TEST(ss2_.empty());
ss_.clear();
ss2_.clear();
ss_.push_back(0);
ss2_.push_back(0);
ss_.splice(ss_.end(),ss2_,ss2_.begin(),ss2_.end());
CHECK_EQUAL(ss_,(0)(0));
BOOST_TEST(ss2_.empty());
ss_.clear();
ss2_.clear();
ss_.push_back(0);
ss2_.push_back(0);
ss_.merge(ss2_);
CHECK_EQUAL(ss_,(0)(0));
BOOST_TEST(ss2_.empty());
typedef typename Sequence::value_type value_type;
ss_.clear();
ss2_.clear();
ss_.push_back(0);
ss2_.push_back(0);
ss_.merge(ss2_,std::less<value_type>());
CHECK_EQUAL(ss_,(0)(0));
BOOST_TEST(ss2_.empty());
}
}
#if BOOST_WORKAROUND(__MWERKS__,<=0x3003)
#pragma parse_func_templ reset
#endif
void test_list_ops()
{
typedef multi_index_container<
int,
indexed_by<
ordered_unique<identity<int> >,
sequenced<>
>
> sequenced_set;
test_list_ops_unique_seq<sequenced_set>();
typedef multi_index_container<
int,
indexed_by<
ordered_unique<identity<int> >,
random_access<>
>
> random_access_set;
test_list_ops_unique_seq<random_access_set>();
typedef multi_index_container<
int,
indexed_by<sequenced<> >
> int_list;
test_list_ops_non_unique_seq<int_list>();
typedef multi_index_container<
int,
indexed_by<random_access<> >
> int_vector;
test_list_ops_non_unique_seq<int_vector>();
}

View File

@@ -0,0 +1,11 @@
/* Boost.MultiIndex test for standard list operations.
*
* Copyright 2003-2008 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
void test_list_ops();

View File

@@ -0,0 +1,18 @@
/* Boost.MultiIndex test for standard list operations.
*
* Copyright 2003-2013 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
#include <boost/detail/lightweight_test.hpp>
#include "test_list_ops.hpp"
int main()
{
test_list_ops();
return boost::report_errors();
}

View File

@@ -0,0 +1,580 @@
/* Boost.MultiIndex test for modifier memfuns.
*
* Copyright 2003-2017 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
#include "test_modifiers.hpp"
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <boost/detail/lightweight_test.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/iterator/iterator_facade.hpp>
#include <boost/move/core.hpp>
#include <boost/next_prior.hpp>
#include <boost/shared_ptr.hpp>
#include <iterator>
#include <vector>
#include "pre_multi_index.hpp"
#include "employee.hpp"
using namespace boost::multi_index;
struct non_copyable_int
{
explicit non_copyable_int(int n_):n(n_){}
non_copyable_int(BOOST_RV_REF(non_copyable_int) x):n(x.n){x.n=0;}
non_copyable_int& operator=(BOOST_RV_REF(non_copyable_int) x)
{
n=x.n;
x.n=0;
return *this;
}
int n;
private:
BOOST_MOVABLE_BUT_NOT_COPYABLE(non_copyable_int)
};
class always_one
{
public:
always_one():n(1){}
~always_one(){n=0;}
int get()const{return n;}
private:
int n;
};
inline bool operator==(const always_one& x,const always_one& y)
{
return x.get()==y.get();
}
#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
namespace boost{
#endif
inline std::size_t hash_value(const always_one& x)
{
return static_cast<std::size_t>(x.get());
}
#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
} /* namespace boost */
#endif
class linked_object
{
struct impl:boost::enable_shared_from_this<impl>
{
typedef boost::shared_ptr<const impl> ptr;
impl(int n_,ptr next_=ptr()):n(n_),next(next_){}
int n;
ptr next;
};
typedef multi_index_container<
impl,
indexed_by<
#if BOOST_WORKAROUND(__IBMCPP__,BOOST_TESTED_AT(1010))
ordered_unique<member<impl,int,&linked_object::impl::n> >,
hashed_non_unique<member<impl,int,&linked_object::impl::n> >,
#else
ordered_unique<member<impl,int,&impl::n> >,
hashed_non_unique<member<impl,int,&impl::n> >,
#endif
sequenced<>,
random_access<>
>
> impl_repository_t;
static impl_repository_t impl_repository;
public:
linked_object(int n):pimpl(init(impl(n))){}
linked_object(int n,const linked_object& x):pimpl(init(impl(n,x.pimpl))){}
private:
impl::ptr init(const impl& x)
{
std::pair<impl_repository_t::iterator,bool> p=impl_repository.insert(x);
if(p.second)return impl::ptr(&*p.first,&erase_impl);
else return p.first->shared_from_this();
}
static void erase_impl(const impl* p)
{
impl_repository.erase(p->n);
}
impl::ptr pimpl;
};
linked_object::impl_repository_t linked_object::impl_repository;
struct tempvalue_iterator:
boost::iterator_facade<
tempvalue_iterator,int,boost::forward_traversal_tag,int>
{
tempvalue_iterator(int n_):n(n_){}
void increment(){++n;}
bool equal(const tempvalue_iterator& x)const{return n==x.n;}
int dereference()const{return n;}
int n;
};
struct change_int
{
change_int(int n):n(n){}
void operator()(int& x)const{x=n;}
int n;
};
#if !(defined BOOST_NO_EXCEPTIONS)
struct change_int_and_throw
{
change_int_and_throw(int n):n(n){}
void operator()(int& x)const{x=n;throw 0;}
int n;
};
#endif
void test_modifiers()
{
employee_set es;
employee_set_by_name& i1=get<name>(es);
employee_set_by_age& i2=get<age>(es);
employee_set_as_inserted& i3=get<as_inserted>(es);
employee_set_by_ssn& i4=get<ssn>(es);
employee_set_randomly& i5=get<randomly>(es);
es.insert(employee(0,"Joe",31,1123));
BOOST_TEST(es.emplace(0,"Joe",31,1123).second==false);
BOOST_TEST(i1.insert(employee(0,"Joe Jr.",5,2563)).second==false);
BOOST_TEST(i2.emplace_hint(i2.end(),1,"Victor",5,1123)->name!="Victor");
BOOST_TEST(i3.insert(i3.begin(),employee(1,"Victor",5,1123)).second
==false);
BOOST_TEST(i3.push_front(employee(0,"Joe Jr.",5,2563)).second==false);
BOOST_TEST(i3.push_back(employee(0,"Joe Jr.",5,2563)).second==false);
BOOST_TEST(i5.emplace_front(1,"Victor",5,1123).second==false);
BOOST_TEST(i5.emplace_back(1,"Victor",5,1123).second==false);
employee_set_by_name::iterator it1=i1.find("Joe");
i1.insert(it1,employee(1,"Joe Jr.",5,2563));
BOOST_TEST(es.size()==2);
employee_set_by_age::iterator it2=i2.find(31);
i2.insert(it2,employee(2,"Grandda Joe",64,7881));
BOOST_TEST(es.size()==3);
employee_set_as_inserted::iterator it3=i3.begin();
i3.insert(it3,100,employee(3,"Judy",39,6201));
BOOST_TEST((--it3)->ssn==6201);
BOOST_TEST(es.size()==4);
employee_set_randomly::iterator it5=i5.begin();
i5.insert(it5,100,employee(4,"Jill",52,3379));
BOOST_TEST(i5.begin()->age==52);
BOOST_TEST(es.size()==5);
es.erase(employee(1,"Joe Jr.",5,2563));
BOOST_TEST(i3.size()==4&&i5.size()==4);
BOOST_TEST(i1.erase("Judy")==1);
BOOST_TEST(es.size()==3&&i2.size()==3);
BOOST_TEST(i2.erase(it2)->age==52);
BOOST_TEST(i3.size()==2&&i4.size()==2);
i3.pop_front();
BOOST_TEST(i1.size()==1&&i2.size()==1);
i5.erase(i5.begin(),i5.end());
BOOST_TEST(es.size()==0&&i3.size()==0);
i5.emplace(i5.end(),0,"Joe",31,1123);
BOOST_TEST(i1.erase(i1.begin())==i1.end());
BOOST_TEST(i1.size()==0);
i1.emplace(0,"Joe",31,1123);
i3.emplace(i3.begin(),1,"Jack",31,5032);
i4.emplace_hint(i4.end(),2,"James",31,3847);
BOOST_TEST(i2.erase(31)==3);
BOOST_TEST(i2.size()==0);
i3.emplace_front(1,"Jack",31,5032);
i3.emplace_back(0,"Joe",31,1123);
BOOST_TEST(i3.front()==employee(1,"Jack",31,5032));
BOOST_TEST(i3.back()==employee(0,"Joe",31,1123));
i3.pop_back();
BOOST_TEST(i3.back()==employee(1,"Jack",31,5032));
BOOST_TEST(es.size()==1);
i3.pop_front();
BOOST_TEST(es.size()==0);
i5.push_back(employee(1,"Jack",31,5032));
i5.push_front(employee(0,"Joe",31,1123));
i5.insert(i5.end()-1,employee(2,"Grandda Joe",64,7881));
BOOST_TEST(i5.back()==employee(1,"Jack",31,5032));
BOOST_TEST(i5.front()==employee(0,"Joe",31,1123));
BOOST_TEST(i5[0]==i5.front()&&i5.at(0)==i5.front());
BOOST_TEST(i5[i5.size()-1]==i5.back()&&i5.at(i5.size()-1)==i5.back());
i5.pop_front();
BOOST_TEST(i5.back()==employee(1,"Jack",31,5032));
BOOST_TEST(i5.front()==employee(2,"Grandda Joe",64,7881));
BOOST_TEST(es.size()==2);
i5.pop_back();
BOOST_TEST(i5.back()==employee(2,"Grandda Joe",64,7881));
BOOST_TEST(i5.front()==i5.front());
BOOST_TEST(es.size()==1);
i5.erase(i5.begin());
BOOST_TEST(es.size()==0);
std::vector<employee> ve;
ve.push_back(employee(3,"Anna",31,5388));
ve.push_back(employee(1,"Rachel",27,9012));
ve.push_back(employee(2,"Agatha",40,1520));
i1.insert(ve.begin(),ve.end());
BOOST_TEST(i2.size()==3);
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
i1.insert({{4,"Vanessa",20,9236},{5,"Penelope",55,2358}});
BOOST_TEST(i2.size()==5);
#endif
BOOST_TEST(i2.erase(i2.begin(),i2.end())==i2.end());
BOOST_TEST(es.size()==0);
i2.insert(ve.begin(),ve.end());
BOOST_TEST(i3.size()==3);
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
i2.insert({{4,"Vanessa",20,9236},{5,"Penelope",55,2358}});
BOOST_TEST(i3.size()==5);
#endif
BOOST_TEST(*(i3.erase(i3.begin()))==employee(1,"Rachel",27,9012));
BOOST_TEST(i3.erase(i3.begin(),i3.end())==i3.end());
BOOST_TEST(es.size()==0);
i3.insert(i3.end(),ve.begin(),ve.end());
BOOST_TEST(es.size()==3);
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
i3.insert(i3.begin(),{{4,"Vanessa",20,9236},{5,"Penelope",55,2358}});
BOOST_TEST(i3.front().name=="Vanessa");
BOOST_TEST(i4.size()==5);
#endif
BOOST_TEST(i4.erase(9012)==1);
i4.erase(i4.begin());
BOOST_TEST(i4.erase(i4.begin(),i4.end())==i4.end());
i4.insert(ve.begin(),ve.end());
BOOST_TEST(i5.size()==3);
BOOST_TEST(i5.erase(i5.begin(),i5.end())==i5.end());
BOOST_TEST(es.size()==0);
i5.insert(i5.begin(),ve.begin(),ve.end());
BOOST_TEST(i1.size()==3);
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
i5.insert(i5.end(),{{4,"Vanessa",20,9236},{5,"Penelope",55,2358}});
BOOST_TEST(i5.back().name=="Penelope");
BOOST_TEST(i1.size()==5);
#endif
BOOST_TEST(es.erase(es.begin(),es.end())==es.end());
BOOST_TEST(i2.size()==0);
es.insert(employee(0,"Joe",31,1123));
es.insert(employee(1,"Robert",27,5601));
es.insert(employee(2,"John",40,7889));
es.insert(employee(3,"Albert",20,9012));
es.insert(employee(4,"John",57,1002));
employee_set es_backup(es);
employee_set es2;
es2.insert(employee(3,"Anna",31,5388));
es2.insert(employee(1,"Rachel",27,9012));
es2.insert(employee(2,"Agatha",40,1520));
employee_set es2_backup(es2);
i1.swap(get<1>(es2));
BOOST_TEST(es==es2_backup&&es2==es_backup);
i2.swap(get<2>(es2));
BOOST_TEST(es==es_backup&&es2==es2_backup);
i3.swap(get<3>(es2));
BOOST_TEST(es==es2_backup&&es2==es_backup);
i4.swap(get<4>(es2));
BOOST_TEST(es==es_backup&&es2==es2_backup);
i5.swap(get<5>(es2));
BOOST_TEST(es==es2_backup&&es2==es_backup);
#if defined(BOOST_FUNCTION_SCOPE_USING_DECLARATION_BREAKS_ADL)
::boost::multi_index::detail::swap(i1,get<1>(es2));
#else
using std::swap;
swap(i1,get<1>(es2));
#endif
BOOST_TEST(es==es_backup&&es2==es2_backup);
#if defined(BOOST_FUNCTION_SCOPE_USING_DECLARATION_BREAKS_ADL)
::boost::multi_index::detail::swap(i2,get<2>(es2));
#else
using std::swap;
swap(i2,get<2>(es2));
#endif
BOOST_TEST(es==es2_backup&&es2==es_backup);
#if defined(BOOST_FUNCTION_SCOPE_USING_DECLARATION_BREAKS_ADL)
::boost::multi_index::detail::swap(i3,get<3>(es2));
#else
using std::swap;
swap(i3,get<3>(es2));
#endif
BOOST_TEST(es==es_backup&&es2==es2_backup);
#if defined(BOOST_FUNCTION_SCOPE_USING_DECLARATION_BREAKS_ADL)
::boost::multi_index::detail::swap(i4,get<4>(es2));
#else
using std::swap;
swap(i4,get<4>(es2));
#endif
BOOST_TEST(es==es2_backup&&es2==es_backup);
#if defined(BOOST_FUNCTION_SCOPE_USING_DECLARATION_BREAKS_ADL)
::boost::multi_index::detail::swap(i5,get<5>(es2));
#else
using std::swap;
swap(i5,get<5>(es2));
#endif
BOOST_TEST(es==es_backup&&es2==es2_backup);
i3.clear();
BOOST_TEST(i3.size()==0);
es=es2;
i4.clear();
BOOST_TEST(i4.size()==0);
es=es2;
i5.clear();
BOOST_TEST(i5.size()==0);
es2.clear();
BOOST_TEST(es2.size()==0);
/* non-copyable elements */
multi_index_container<
non_copyable_int,
indexed_by<
ordered_non_unique<member<non_copyable_int,int,&non_copyable_int::n> >,
hashed_non_unique<member<non_copyable_int,int,&non_copyable_int::n> >,
sequenced<>,
random_access<>
>
> ncic,ncic2;
ncic.emplace(1);
get<1>(ncic).emplace(1);
get<2>(ncic).emplace_back(1);
get<3>(ncic).emplace_back(1);
non_copyable_int nci(1);
ncic.insert(boost::move(nci));
BOOST_TEST(nci.n==0);
nci.n=1;
get<1>(ncic).insert(boost::move(nci));
BOOST_TEST(nci.n==0);
nci.n=1;
get<2>(ncic).push_back(boost::move(nci));
BOOST_TEST(nci.n==0);
nci.n=1;
get<3>(ncic).push_back(boost::move(nci));
BOOST_TEST(nci.n==0);
std::vector<int> vi(4,1);
const std::vector<int>& cvi=vi;
ncic.insert(vi.begin(),vi.end());
ncic.insert(cvi.begin(),cvi.end());
get<2>(ncic).insert(get<2>(ncic).begin(),vi.begin(),vi.end());
get<2>(ncic).insert(get<2>(ncic).begin(),cvi.begin(),cvi.end());
BOOST_TEST(ncic.count(1)==24);
ncic.swap(ncic2);
BOOST_TEST(ncic.empty());
BOOST_TEST(ncic2.count(1)==24);
/* testcase for problem reported at
* http://lists.boost.org/boost-users/2006/12/24215.php
*/
multi_index_container<
always_one,
indexed_by<
hashed_non_unique<identity<always_one> >
>
> aoc;
aoc.insert(always_one());
aoc.insert(always_one());
aoc.erase(*(aoc.begin()));
BOOST_TEST(aoc.empty());
/* Testcases for compliance with "as close to hint as possible"
* proposed behavior for associative containers:
* http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#233
* http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1780.html
*/
typedef multi_index_container<
int,
indexed_by<
ordered_non_unique<identity<int> >
>
> int_non_unique_container;
int_non_unique_container c;
c.insert(0);c.insert(0);
c.insert(1);c.insert(1);
c.insert(2);c.insert(2);
BOOST_TEST(std::distance(c.begin(),c.insert(c.begin(),1))==2);
BOOST_TEST(std::distance(c.begin(),c.insert(boost::next(c.begin()),1))==2);
BOOST_TEST(std::distance(c.begin(),c.insert(c.lower_bound(1),1))==2);
BOOST_TEST(
std::distance(c.begin(),c.insert(boost::next(c.lower_bound(1)),1))==3);
BOOST_TEST(std::distance(c.begin(),c.insert(c.upper_bound(1),1))==8);
BOOST_TEST(std::distance(c.begin(),c.insert(boost::prior(c.end()),1))==9);
BOOST_TEST(std::distance(c.begin(),c.insert(c.end(),1))==10);
/* testcase for erase() reentrancy */
{
linked_object o1(1);
linked_object o2(2,o1);
o1=o2;
}
/* testcases for bug reported at
* https://svn.boost.org/trac/boost/ticket/9665
*/
{
multi_index_container<
int,
indexed_by<hashed_unique<identity<int> > >
> hc;
hc.insert(tempvalue_iterator(0),tempvalue_iterator(10));
BOOST_TEST(hc.size()==10);
multi_index_container<
int,
indexed_by<ordered_unique<identity<int> > >
> oc;
oc.insert(tempvalue_iterator(0),tempvalue_iterator(10));
BOOST_TEST(oc.size()==10);
}
/* testcases for https://svn.boost.org/trac10/ticket/12542 */
{
multi_index_container<
int,
indexed_by<
ordered_unique<identity<int> >,
hashed_unique<identity<int> >
>
> ohc;
#if !(defined BOOST_NO_EXCEPTIONS)
ohc.insert(0);
ohc.insert(1);
try{
ohc.modify_key(ohc.begin(),change_int_and_throw(1));
}
catch(int){}
BOOST_TEST(ohc.size()==1);
ohc.clear();
ohc.insert(0);
ohc.insert(1);
try{
ohc.modify_key(ohc.begin(),change_int_and_throw(1),change_int(0));
}
catch(int){}
BOOST_TEST(ohc.size()==1);
ohc.clear();
ohc.insert(0);
ohc.insert(1);
try{
ohc.modify_key(
ohc.begin(),change_int_and_throw(1),change_int_and_throw(0));
}
catch(int){}
BOOST_TEST(ohc.size()==1);
ohc.clear();
ohc.insert(0);
ohc.insert(1);
try{
ohc.modify_key(ohc.begin(),change_int(1),change_int_and_throw(0));
}
catch(int){}
BOOST_TEST(ohc.size()==1);
ohc.clear();
#endif
ohc.insert(0);
ohc.insert(1);
ohc.modify_key(ohc.begin(),change_int(1),change_int(1));
BOOST_TEST(ohc.size()==1);
ohc.clear();
}
}

View File

@@ -0,0 +1,11 @@
/* Boost.MultiIndex test for modifier memfuns.
*
* Copyright 2003-2008 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
void test_modifiers();

View File

@@ -0,0 +1,20 @@
/* Boost.MultiIndex test for modifier memfuns.
*
* Copyright 2003-2013 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
#include <boost/detail/lightweight_test.hpp>
#include "test_modifiers.hpp"
int main()
{
test_modifiers();
return boost::report_errors();
}

View File

@@ -0,0 +1,75 @@
/* Boost.MultiIndex test for MPL operations.
*
* Copyright 2003-2008 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
#include "test_mpl_ops.hpp"
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include "pre_multi_index.hpp"
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/mpl/at.hpp>
#include <boost/mpl/list.hpp>
using namespace boost::multi_index;
void test_mpl_ops()
{
typedef multi_index_container<
int,
indexed_by<
ordered_unique<identity<int> >,
ordered_non_unique<identity<int> >
>
> indexed_t1;
BOOST_STATIC_ASSERT((boost::is_same<
boost::mpl::at_c<indexed_t1::index_specifier_type_list,0>::type,
ordered_unique<identity<int> > >::value));
BOOST_STATIC_ASSERT((boost::is_same<
boost::mpl::at_c<indexed_t1::index_specifier_type_list,1>::type,
ordered_non_unique<identity<int> > >::value));
typedef boost::mpl::push_front<
indexed_t1::index_specifier_type_list,
sequenced<>
>::type index_list_t;
typedef multi_index_container<
int,
index_list_t
> indexed_t2;
BOOST_STATIC_ASSERT((boost::is_same<
boost::mpl::at_c<indexed_t2::index_specifier_type_list,0>::type,
sequenced<> >::value));
BOOST_STATIC_ASSERT((boost::is_same<
boost::mpl::at_c<indexed_t2::index_specifier_type_list,1>::type,
boost::mpl::at_c<indexed_t1::index_specifier_type_list,0>::type>::value));
BOOST_STATIC_ASSERT((boost::is_same<
boost::mpl::at_c<indexed_t2::index_specifier_type_list,2>::type,
boost::mpl::at_c<indexed_t1::index_specifier_type_list,1>::type>::value));
typedef multi_index_container<
int,
boost::mpl::list<
ordered_unique<identity<int> >,
ordered_non_unique<identity<int> >
>
> indexed_t3;
BOOST_STATIC_ASSERT((boost::is_same<
boost::mpl::at_c<indexed_t3::index_specifier_type_list,0>::type,
boost::mpl::at_c<indexed_t1::index_specifier_type_list,0>::type>::value));
BOOST_STATIC_ASSERT((boost::is_same<
boost::mpl::at_c<indexed_t3::index_specifier_type_list,1>::type,
boost::mpl::at_c<indexed_t1::index_specifier_type_list,1>::type>::value));
}

View File

@@ -0,0 +1,11 @@
/* Boost.MultiIndex test for for MPL operations.
*
* Copyright 2003-2008 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
void test_mpl_ops();

View File

@@ -0,0 +1,18 @@
/* Boost.MultiIndex test for for MPL operations.
*
* Copyright 2003-2013 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
#include <boost/detail/lightweight_test.hpp>
#include "test_mpl_ops.hpp"
int main()
{
test_mpl_ops();
return boost::report_errors();
}

View File

@@ -0,0 +1,56 @@
/* Boost.MultiIndex test for observer memfuns.
*
* Copyright 2003-2013 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
#include "test_observers.hpp"
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <algorithm>
#include <vector>
#include "pre_multi_index.hpp"
#include "employee.hpp"
#include <boost/detail/lightweight_test.hpp>
using namespace boost::multi_index;
void test_observers()
{
employee_set es;
const employee_set_by_name& i1=get<by_name>(es);
const employee_set_by_age& i2=get<age>(es);
es.insert(employee(0,"Joe",31,1123));
es.insert(employee(1,"Robert",27,5601));
es.insert(employee(2,"John",40,7889));
es.insert(employee(3,"Albert",20,9012));
es.insert(employee(4,"John",57,1002));
{
employee_set_by_name::key_from_value k=i1.key_extractor();
employee_set_by_name::hasher h=i1.hash_function();
employee_set_by_name::key_equal eq=i1.key_eq();
employee_set_by_name::const_iterator it0=i1.equal_range("John").first;
employee_set_by_name::const_iterator it1=it0;++it1;
BOOST_TEST(k(*it0)=="John"&&k(*it1)=="John");
BOOST_TEST(h(k(*it0))==h(k(*it1)));
BOOST_TEST(eq(k(*it0),k(*it1))==true);
}
{
employee_set_by_age::key_from_value k=i2.key_extractor();
employee_set_by_age::key_compare c=i2.key_comp();
employee_set_by_age::value_compare vc=i2.value_comp();
employee_set_by_age::const_iterator it0=i2.find(31);
employee_set_by_age::const_iterator it1=i2.find(40);
BOOST_TEST(k(*it0)==31&&k(*it1)==40);
BOOST_TEST(c(k(*it0),k(*it1))==true);
BOOST_TEST(vc(*it0,*it1)==true);
}
}

View File

@@ -0,0 +1,11 @@
/* Boost.MultiIndex test for observer memfuns.
*
* Copyright 2003-2008 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
void test_observers();

View File

@@ -0,0 +1,18 @@
/* Boost.MultiIndex test for observer memfuns.
*
* Copyright 2003-2013 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
#include <boost/detail/lightweight_test.hpp>
#include "test_observers.hpp"
int main()
{
test_observers();
return boost::report_errors();
}

View File

@@ -0,0 +1,135 @@
/* Boost.MultiIndex test for projection capabilities.
*
* Copyright 2003-2013 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*/
#include "test_projection.hpp"
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include "pre_multi_index.hpp"
#include "employee.hpp"
#include <boost/detail/lightweight_test.hpp>
using namespace boost::multi_index;
void test_projection()
{
employee_set es;
es.insert(employee(0,"Joe",31,1123));
es.insert(employee(1,"Robert",27,5601));
es.insert(employee(2,"John",40,7889));
es.insert(employee(3,"Albert",20,9012));
es.insert(employee(4,"John",57,1002));
employee_set::iterator it,itbis;
employee_set_by_name::iterator it1;
employee_set_by_age::iterator it2;
employee_set_as_inserted::iterator it3;
employee_set_by_ssn::iterator it4;
employee_set_randomly::iterator it5;
BOOST_STATIC_ASSERT((boost::is_same<
employee_set::iterator,
nth_index_iterator<employee_set,0>::type >::value));
BOOST_STATIC_ASSERT((boost::is_same<
employee_set_by_name::iterator,
nth_index_iterator<employee_set,1>::type >::value));
#if defined(BOOST_NO_MEMBER_TEMPLATES)
BOOST_STATIC_ASSERT((boost::is_same<
employee_set_by_age::iterator,
index_iterator<employee_set,age>::type >::value));
#else
BOOST_STATIC_ASSERT((boost::is_same<
employee_set_by_age::iterator,
employee_set::index_iterator<age>::type >::value));
#endif
BOOST_STATIC_ASSERT((boost::is_same<
employee_set_as_inserted::iterator,
nth_index_iterator<employee_set,3>::type >::value));
BOOST_STATIC_ASSERT((boost::is_same<
employee_set_by_ssn::iterator,
nth_index_iterator<employee_set,4>::type >::value));
BOOST_STATIC_ASSERT((boost::is_same<
employee_set_randomly::iterator,
nth_index_iterator<employee_set,5>::type >::value));
it= es.find(employee(1,"Robert",27,5601));
it1= project<name>(es,it);
it2= project<age>(es,it1);
it3= project<as_inserted>(es,it2);
it4= project<ssn>(es,it3);
it5= project<randomly>(es,it4);
#if defined(BOOST_NO_MEMBER_TEMPLATES)
itbis=project<0>(es,it5);
#else
itbis=es.project<0>(it5);
#endif
BOOST_TEST(
*it==*it1&&*it1==*it2&&*it2==*it3&&*it3==*it4&&*it4==*it5&&itbis==it);
BOOST_TEST(project<name>(es,es.end())==get<name>(es).end());
BOOST_TEST(project<age>(es,es.end())==get<age>(es).end());
BOOST_TEST(project<as_inserted>(es,es.end())==get<as_inserted>(es).end());
BOOST_TEST(project<ssn>(es,es.end())==get<ssn>(es).end());
BOOST_TEST(project<randomly>(es,es.end())==get<randomly>(es).end());
const employee_set& ces=es;
employee_set::const_iterator cit,citbis;
employee_set_by_name::const_iterator cit1;
employee_set_by_age::const_iterator cit2;
employee_set_as_inserted::const_iterator cit3;
employee_set_by_ssn::const_iterator cit4;
employee_set_randomly::const_iterator cit5;
BOOST_STATIC_ASSERT((boost::is_same<
employee_set::const_iterator,
nth_index_const_iterator<employee_set,0>::type >::value));
BOOST_STATIC_ASSERT((boost::is_same<
employee_set_by_name::const_iterator,
nth_index_const_iterator<employee_set,1>::type >::value));
#if defined(BOOST_NO_MEMBER_TEMPLATES)
BOOST_STATIC_ASSERT((boost::is_same<
employee_set_by_age::const_iterator,
index_const_iterator<employee_set,age>::type >::value));
#else
BOOST_STATIC_ASSERT((boost::is_same<
employee_set_by_age::const_iterator,
employee_set::index_const_iterator<age>::type >::value));
#endif
BOOST_STATIC_ASSERT((boost::is_same<
employee_set_as_inserted::const_iterator,
nth_index_const_iterator<employee_set,3>::type >::value));
BOOST_STATIC_ASSERT((boost::is_same<
employee_set_by_ssn::const_iterator,
nth_index_const_iterator<employee_set,4>::type >::value));
BOOST_STATIC_ASSERT((boost::is_same<
employee_set_randomly::const_iterator,
nth_index_const_iterator<employee_set,5>::type >::value));
cit= ces.find(employee(4,"John",57,1002));
#if defined(BOOST_NO_MEMBER_TEMPLATES)
cit1= project<by_name>(ces,cit);
#else
cit1= ces.project<by_name>(cit);
#endif
cit2= project<age>(ces,cit1);
#if defined(BOOST_NO_MEMBER_TEMPLATES)
cit3= project<as_inserted>(ces,cit2);
#else
cit3= ces.project<as_inserted>(cit2);
#endif
cit4= project<ssn>(ces,cit3);
cit5= project<randomly>(ces,cit4);
citbis=project<0>(ces,cit5);
BOOST_TEST(
*cit==*cit1&&*cit1==*cit2&&*cit2==*cit3&&*cit3==*cit4&&*cit4==*cit5&&
citbis==cit);
}

Some files were not shown because too many files have changed in this diff Show More