commit b35bef74e475a3735d105d440bd0f5f6f2382c42
Author: JoaquÃn M. López Muñoz
+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. Rosa
+Bernárdez proofread the last version of the tutorial.
+
+Pavel Vožení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!
+
+The Boost acceptance review took place between March 20th and 30th 2004.
+Pavel Vožení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ö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.
+
+Boost.MultiIndex could not have been written without Aleksey Gurtovoy
+et al. superb Boost MPL
+Library. Also, Aleksey's techniques for dealing with ETI-related
+problems in MSVC++ 6.0 helped solve some internal issues of the library.
+
+The internal implementation of red-black trees is based on that of SGI STL
+stl_tree.h file:
+
+ Revised May 7th 2004 Copyright © 2003-2004 Joaquín M López Muñoz.
+Use, modification, and distribution are subject to the Boost Software
+License, Version 1.0. (See accompanying file
+LICENSE_1_0.txt or copy at
+www.boost.org/LICENSE_1_0.txt)
+
+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
+
+
+
+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:
+
+On the other hand, partial searches without specifying the first keys are not
+allowed.
+
+By default, the corresponding
+See Example 7 in the examples section
+for an application of
+The
+This possibility is fully exploited by predefined key extractors provided
+by Boost.MultiIndex, making it simpler to define
+Note that this is specified in exactly the same manner as a
+In fact, support for pointers is further extended to accept what we call
+chained pointers. 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 to another chained pointer; 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
+
+
+
+Boost.MultiIndex Acknowledgements
+
+
+
+
+Copyright (c) 1996,1997
+Silicon Graphics Computer Systems, Inc.
+
+
+
+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 "as is" without express or implied warranty.
+
+
+Copyright (c) 1994
+Hewlett-Packard Company
+
+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 "as is" without express or implied warranty.
+
+I would like to dedicate this piece of work to Rosa Berná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ópez (2001-2003): he
+lived too fast, died too young.
+
+
+
+
+
+
+
+
+
+
+
+
+
+Boost.MultiIndex Advanced topics
+
+
+
+Contents
+
+
+
+
+ctor_args_list
multi_index_container
+
+ multi_index_container
+
+
+ Composite keys
+
+composite_key
, as shown in the example:
+
+
+
+struct phonebook_entry
+{
+ std::string family_name;
+ std::string given_name;
+ std::string phone_number;
+
+ phonebook_entry(
+ std::string family_name,
+ std::string given_name,
+ std::string phone_number):
+ family_name(family_name),given_name(given_name),phone_number(phone_number)
+ {}
+};
+
+// define a multi_index_container with a composite key on
+// (family_name,given_name)
+typedef multi_index_container<
+ phonebook_entry,
+ indexed_by<
+ //non-unique as some subscribers might have more than one number
+ ordered_non_unique<
+ composite_key<
+ phonebook_entry,
+ member<phonebook_entry,std::string,&phonebook_entry::family_name>,
+ member<phonebook_entry,std::string,&phonebook_entry::given_name>
+ >
+ >,
+ ordered_unique< // unique as numbers belong to only one subscriber
+ member<phonebook_entry,std::string,&phonebook_entry::phone_number>
+ >
+ >
+> phonebook;
+
composite_key
accepts two or more key extractors on the same
+value (here, phonebook_entry
). Lookup operations on a composite
+key are accomplished by passing tuples with the values searched:
+
+
+
+phonebook pb;
+...
+// search for Dorothea White's number
+phonebook::iterator it=pb.find(
+ boost::make_tuple(std::string("White"),std::string("Dorothea")));
+std::string number=it->phone_number;
+
+
+
+phonebook pb;
+...
+// look for all Whites
+std::pair<phonebook::iterator,phonebook::iterator> p=
+ pb.equal_range(boost::make_tuple(std::string("White")));
+
std::less
predicate is used
+for each subkey of a composite key. Alternate comparison predicates can
+be specified with
+composite_key_compare
:
+
+
+
+// phonebook with given names in reverse order
+
+typedef multi_index_container<
+ phonebook_entry,
+ indexed_by<
+ ordered_non_unique<
+ composite_key<
+ phonebook_entry,
+ member<phonebook_entry,std::string,&phonebook_entry::family_name>,
+ member<phonebook_entry,std::string,&phonebook_entry::given_name>
+ >,
+ composite_key_compare<
+ std::less<std::string>, // family names sorted as by default
+ std::greater<std::string> // given names reversed
+ >
+ >,
+ ordered_unique<
+ member<phonebook_entry,std::string,&phonebook_entry::phone_number>
+ >
+ >
+> phonebook;
+
composite_key
.
+Advanced features of Boost.MultiIndex key
+extractors
+
+Key Extractor
+concept allows the same object to extract keys from several different types,
+possibly through suitably defined overloads of operator()
:
+
+
+
+// example of a name extractor from employee and employee *
+struct name_extractor
+{
+ const std::string& operator()(const employee& e)const{return e.name;}
+ std::string& operator()(employee& e)const{return e.name;}
+ std::string& operator()(employee* e)const{return e->name;}
+};
+
multi_index_container
s
+where elements are pointers or references to the actual objects. The following
+specifies a multi_index_container
of pointers to employees sorted by their
+names.
+
+
+
+typedef multi_index_container<
+ employee *,
+ indexed_by<
+ ordered_non_unique<member<employee,std::string,&employee::name> > >
+> employee_set;
+
multi_index_container
+of actual employee
objects: member
takes care of the
+extra dereferencing needed to gain access to employee::name
. A similar
+functionality is provided for interoperability with reference wrappers from
+Boost.Ref:
+
+
+
+typedef multi_index_container<
+ boost::reference_wrapper<const employee>,
+ indexed_by<
+ ordered_non_unique<member<employee,std::string,&employee::name> > >
+> employee_set;
+
employee
are:
+
+
+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 employee *
,const employee *
,std::auto_ptr<employee>
,std::list<boost::reference_wrapper<employee> >::iterator
,employee **
,boost::shared_ptr<const employee *>
.multi_index_container
s from preexisting
+multi_index_container
s.
+
+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: +
+ ++ ++struct T +{ + int i; + const int j; + int f()const; + int g(); +}; +
+The table below lists the appropriate key extractors to be used for
+different pointer and reference wrapper types based on T
, for
+each of its members.
+
+
element type | +sorted by | +key extractor | +applicable toconst elements? |
+ read/write? | +
---|---|---|---|---|
T |
+ i |
+ member<T,int,&T::i> |
+ yes | +yes | +
j |
+ member<T,const int,&T::j> |
+ yes | +no | +|
f() |
+ const_mem_fun<T,int,&T::f> |
+ yes | +no | +|
g() |
+ mem_fun<T,int,&T::g> |
+ no | +no | +|
reference_wrapper<T> |
+ i |
+ member<T,int,&T::i> |
+ yes | +yes | +
j |
+ member<T,const int,&T::j> |
+ yes | +no | +|
f() |
+ const_mem_fun<T,int,&T::f> |
+ yes | +no | +|
g() |
+ mem_fun<T,int,&T::g> |
+ yes | +no | +|
reference_wrapper<const T> |
+ i |
+ member<T,const int,&T::i> |
+ yes | +no | +
j |
+ member<T,const int,&T::j> |
+ yes | +no | +|
f() |
+ const_mem_fun<T,int,&T::f> |
+ yes | +no | +|
g() |
+ + | |||
chained pointer to T + or to reference_wrapper<T> |
+ i |
+ member<T,int,&T::i> |
+ yes | +yes | +
j |
+ member<T,const int,&T::j> |
+ yes | +no | +|
f() |
+ const_mem_fun<T,int,&T::f> |
+ yes | +no | +|
g() |
+ mem_fun<T,int,&T::g> |
+ yes | +no | +|
chained pointer to const T + or to reference_wrapper<const T> |
+ i |
+ member<T,const int,&T::i> |
+ yes | +no | +
j |
+ member<T,const int,&T::j> |
+ yes | +no | +|
f() |
+ const_mem_fun<T,int,&T::f> |
+ yes | +no | +|
g() |
+ + |
+The column "applicable to const
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
+T
objects). The only negative case is for T::g
when
+the elements are raw T
objects, which make sense as we are dealing
+with a non-constant member function: this also implies that multi_index_container
s
+of elements of T
cannot be sorted by T::g
, because
+elements contained within a multi_index_container
are treated as constant.
+
+A key extractor is called read/write if it returns a non-constant reference
+to the key when passed a non-constant element, and it is called read-only
+otherwise. In order to use multi_index_container::modify_key
, the associated
+key extractor must be read/write. The column "read/write?" shows that most
+combinations yield read-only extractors.
+
+Some care has to be taken to preserve const
-correctness in the
+specification of the key extractors: in some sense, the const
+qualifier is carried along to the member part, even if that particular
+member is not defined as const
. For instance, if the elements
+are of type const T *
, sorting by T::i
is not
+specified as member<const T,int,&T::i>
, but rather as
+member<T,const int,&T::i>
.
+
+For practical demonstrations of use of these key extractors, refer to +example 2 and +example 6 in the examples section. +
+ +member_offset
+The member
key extractor poses some problems in compilers
+that do not properly support pointers to members as non-type
+template arguments. The following compilers have been confirmed not
+to work correctly with member
:
+
member_offset
+has been provided that does the work of member
at the
+expense of less convenient notation and the possibility of
+non-conformance with the standard. Please consult
+the reference for further information on member_offset
.
++ +
+The following test program can help determine if your compiler +properly supports pointers to members as non-type template parameters: +
+ ++ ++#include <boost/multi_index_container/member.hpp> +#include <utility> +#include <iostream> + +using namespace std; +using boost::multi_index::member; + +typedef std::pair<int,int> pair_of_ints; + +int main() +{ + pair_of_ints p(0,1); + int i=member<pair_of_ints,int,&pair_of_ints::first>()(p); + int j=member<pair_of_ints,int,&pair_of_ints::second>()(p); + if(i!=0||j!=1){ + cout<<"WARNING: compiler does not properly support\n" + "pointers as non-type template parameters"<<endl; + return 1; + } + + cout<<"test succesful"<<endl; + return 0; +} + +
+If you find a compiler not listed here that does not pass the test, +please report to the maintainer of the library. As an example of use, +given the class
+ ++ ++class A +{ + int x; +} +
+the instantiation member<A,int,&A::x>
can be simulated then
+as member_offset<A,int,offsetof(A,x)>
.
+
+For those writing portable code, Boost.MultiIndex provides the ternary macro
+BOOST_MULTI_INDEX_MEMBER
. Continuing with the example above, the
+expression
+
+ ++BOOST_MULTI_INDEX_MEMBER(A,int,x) +
+expands to either +
+ ++ ++member<A,int,&A::x> +
+or alternatively to +
+ ++ ++member_offset<A,int,offsetof(A,x)> +
+depending on whether the current compiler supports pointer to members as
+non-type template arguments or not. The alternative expansion is driven by
+the defect macro BOOST_NO_POINTER_TO_MEMBER_TEMPLATE_PARAMETERS
,
+which has been proposed for inclusion in the
+Boost Configuration Library.
+Until the defect macro is accepted, Boost.MultiIndex treats it as if defined for
+
BOOST_MULTI_INDEX_MEMBER
by manually defining
+BOOST_NO_POINTER_TO_MEMBER_TEMPLATE_PARAMETERS
prior to the
+inclusion of Boost.MultiIndex headers.
+
+
+const_mem_fun_explicit
and
+mem_fun_explicit
+MSVC++ 6.0 has problems with const
member functions as non-type
+template parameters, and thus does not accept the const_mem_fun
+key extractor. A simple workaround, fortunately, has been found, consisting
+in specifying the type of these pointers as an additional template
+parameter. The alternative const_mem_fun_explicit
extractor
+adopts this solution; for instance, given the type
+
+ ++struct A +{ + int f()const; +}; +
+the extractor const_mem_fun<A,int,&A::f>
can be replaced by
+const_mem_fun_explicit<A,int,int (A::*)()const,&A::f>
. A similar
+mem_fun_explicit
class template is provided for non-constant
+member functions.
+
+If you are writing cross-platform code, the selection of either key extractor
+is transparently handled by the macro BOOST_MULTI_INDEX_CONST_MEM_FUN
,
+so that
+
+ ++BOOST_MULTI_INDEX_CONST_MEM_FUN(A,int,f) +
+expands by default to +
+ ++ ++const_mem_fun<A,int,&A::f> +
+but resolves to +
+ ++ ++const_mem_fun_explicit<A,int,int (A::*)()const,&A::f> +
+in MSVC++ 6.0. An analogous macro BOOST_MULTI_INDEX_MEM_FUN
is
+provided as well.
+
composite_key
in compilers
+without partial template specialization
+Much of the power of composite_key
derives from the ability
+to perform searches when only the first elements of the compound key are
+given. In order to enable this functionality, std::less
and
+std::greater
are specialized for
+
+composite_key_result
instantiations to provide
+overloads accepting tuples of values.
+
+In those compilers that do not support partial template specialization,
+tuple-based comparisons are not available by default. In this case,
+multi_index_container
instantiations using composite keys
+will work as expected (elements are sorted lexicographically on the
+results of the combined keys), except that lookup operations will not
+accept tuples as an argument. The most obvious workaround
+to this deficiency involves explicitly specifying the comparison
+predicate with composite_key_compare
: this is tedious as
+the comparison predicates for all the element key extractors must be
+explicitly typed. For this reason, Boost.MultiIndex provides the replacement
+class template
+
+composite_key_result_less
, that
+acts as the missing specialization of std::less
for
+composite_key_result
s:
+
+ ++typedef composite_key< + phonebook_entry, + member<phonebook_entry,std::string,&phonebook_entry::family_name>, + member<phonebook_entry,std::string,&phonebook_entry::given_name> +> ckey_t; + +typedef multi_index_container< + phonebook_entry, + indexed_by< + ordered_non_unique< + ckey_t, + // composite_key_result_less plays the role of + // std::less<ckey_t::result_type> + composite_key_result_less<ckey_t::result_type> + >, + ordered_unique< + member<phonebook_entry,std::string,&phonebook_entry::phone_number> + > + > +> phonebook; +
+There is also an analogous
+
+composite_key_result_greater
class to substitute for
+specializations of std::greater
.
+
ctor_args_list
+Although in most cases multi_index_container
s will be default constructed
+(or copied from a preexisting multi_index_container
), 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:
+
+ ++// example of non-default constructed std::set +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; +}; + +typedef std::set<unsigned int,modulo_less<unsigned int> > modulo_set; + +modulo_set m(modulo_less<unsigned int>(10)); +
+multi_index_container
does also provide this functionality, though in a
+considerably more complex fashion, due to the fact that the constructor
+of a multi_index_container
has to accept values for all the internal
+objects of its indices. The full form of multi_index_container
constructor
+is
+
+ ++explicit multi_index_container( + const ctor_args_list& args_list=ctor_args_list(), + const allocator_type& al=allocator_type()); +
+The specification of the allocator object poses no particular problems;
+as for the ctor_args_list
, this object is designed so as to hold
+the necessary construction values for every index in the multi_index_container
.
+From the point of view of the user, ctor_args_list
is equivalent
+to the type
+
+ ++boost::tuple<C0,...,CI-1> +
+where I
is the number of indices, and Ci
is
+
+ ++nth_index<i>::type::ctor_args +
+that is, the nested type ctor_args
of the i
-th index. Each
+ctor_args
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, while sequenced indices do not need any construction
+argument. For instance, given the definition
+
+ ++typedef multi_index_container< + unsigned int, + indexed_by< + ordered_unique<identity<unsigned int> >, + ordered_non_unique<identity<unsigned int>, modulo_less<unsigned int> >, + sequenced<> + > +> modulo_indexed_set; +
+the corresponding ctor_args_list
type is equivalent to
+
+ ++boost::tuple< + // ctr_args of index #0 + boost::tuple<identity<unsigned int>,std::less<unsigned int> >, + + // ctr_args of index #1 + boost::tuple<identity<unsigned int>,modulo_less<unsigned int> >, + + // sequenced indices do not have any construction argument + boost::tuple<> +> +
+Such a modulo_indexed_set
cannot be default constructed, because
+modulo_less
does not provide a default constructor. The following shows
+how the construction can be done:
+
+ ++modulo_indexed_set::ctor_args_list args_list= + boost::make_tuple( + // ctor_args for index #0 is default constructible + modulo_indexed_set::nth_index<0>::type::ctor_args(), + + boost::make_tuple(identity<unsigned int>(),modulo_less<unsigned int>(10)), + + // this is also default constructible (actually, an empty tuple) + modulo_indexed_set::nth_index<2>::type::ctor_args(), + ); + +modulo_indexed_set m(args_list); +
+A program is provided in the examples section that +puts in practise these concepts. +
+ +
+The concept of Design by Contract, originally developed as part
+of Bertrand Meyer's Eiffel language,
+revolves around the formulation of a contract between the user
+of a library and the implementor, by which the first is required to
+respect some preconditions on the values passed when invoking
+methods of the library, and the implementor guarantees in return
+that certain constraints on the results are met (postconditions),
+as well as the honoring of specified internal consistency rules, called
+invariants. Eiffel natively supports the three parts of the
+contract just described by means of constructs require
,
+ensure
and invariant
, respectively.
+
+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: +
+The idea of adding precondition checking facilities to STL as a debugging aid +was first introduced by Cay S. Horstmann in his +Safe STL library and later +adopted by STLport Debug +Mode. Similarly, Boost.MultiIndex features the so-called safe mode +in which all sorts of preconditions are checked when dealing with iterators +and functions of the library. +
+ +
+Boost.MultiIndex safe mode is set by globally defining the macro
+BOOST_MULTI_INDEX_ENABLE_SAFE_MODE
. Error conditions
+are checked via the macro BOOST_MULTI_INDEX_SAFE_MODE_ASSERT
, which
+by default resolves to a call to
+BOOST_ASSERT
.
+
+If the user decides to define her own version of
+BOOST_MULTI_INDEX_SAFE_MODE_ASSERT
, it has to take the form
+
+ ++BOOST_MULTI_INDEX_SAFE_MODE_ASSERT(expr,error_code) +
+where expr
is the condition checked and error_code
+is one value of the safe_mode::error_code
enumeration:
+
+ ++namespace boost{ + +namespace multi_index{ + +namespace safe_mode{ + +enum error_code +{ + invalid_iterator, // default initialized iterator + not_dereferenceable_iterator, // iterator is not dereferenceable + not_incrementable_iterator, // iterator points to end of sequence + not_decrementable_iterator, // iterator points to beginning of sequence + not_owner, // iterator does not belong to the container + not_same_owner, // iterators belong to different containers + invalid_range, // last not reachable from first + inside_range, // iterator lies within a range (and it mustn't) + same_container // containers ought to be different +}; + +} // namespace multi_index::safe_mode + +} // namespace multi_index + +} // namespace boost +
+For instance, the following replacement of
+BOOST_MULTI_INDEX_SAFE_MODE_ASSERT
throws an exception instead of
+asserting:
+
+ ++#include <boost/multi_index_container/safe_mode_errors.hpp> + +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);} + +// This has to go before the inclusion of any header from Boost.MultiIndex, +// except possibly safe_error_codes.hpp. +
+Other possibilites, like outputting to a log or firing some kind of alert, are +also implementable. +
+ +
+Warning: 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
+NDEBUG
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.
+
+The so called invariant-checking mode of Boost.MultiIndex can be
+set by globally defining the macro
+BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING
.
+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.
+
+If an invariant test fails, Boost.MultiIndex will indicate the failure
+by means of the unary macro BOOST_MULTI_INDEX_INVARIANT_ASSERT
.
+Unless the user provides a definition for this macro, it defaults to
+
+BOOST_ASSERT
. 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.
+
+It is recommended that users of Boost.MultiIndex always set the +invariant-checking mode in debug builds. +
+ +multi_index_container
+Academic movitations aside, there is a practical interest in simulating standard
+associative containers by means of multi_index_container
, namely to take
+advantage of extended functionalities provided by multi_index_container
for
+lookup, range querying and updating.
+
+In order to simulate a std::set
one can follow the substitution
+rule:
+
+ ++std::set<Key,Compare,Allocator> -> + multi_index_container< + Key, + indexed_by<ordered_unique<identity<Key>,Compare> >, + Allocator + > +
+In the default case where Compare=std::less<Key>
and
+Allocator=std::allocator<Key>
, the substitution rule is
+simplified as
+
+ ++std::set<Key> -> multi_index_container<Key> +
+The substitution of multi_index_container
for std::set
keeps
+the whole set of functionality provided by std::set
, so in
+principle it is a drop-in replacement needing no further adjustments.
+
+std::multiset
can be simulated in a similar manner, according to the
+following rule:
+
+ ++std::multiset<Key,Compare,Allocator> -> + multi_index_container< + Key, + indexed_by<ordered_non_unique<identity<Key>,Compare> >, + Allocator + > +
+When default values are taken into consideration, the rule takes the form +
+ ++ ++std::multiset<Key> -> + multi_index_container< + Key, + indexed_by<ordered_non_unique<identity<Key> > > + > +
+The simulation of std::multiset
s with multi_index_container
+results in a slight difference with respect to the interface offered: the member
+function insert(const value_type&)
does not return an
+iterator
as in std::multiset
s, but rather a
+std::pair<iterator,bool>
in the spirit of std::set
s.
+In this particular case, however, the bool
member of the returned
+pair is always true
.
+
+The case of std::map
s and std::multimap
s does not lend
+itself to such a direct simulation by means of multi_index_container
. The main
+problem lies in the fact that elements of a multi_index_container
are treated
+as constant, while the std::map
and std::multimap
handle
+objects of type std::pair<const Key,T>
, thus allowing for free
+modification of the value part. To overcome this difficulty we need to create an ad
+hoc pair class:
+
+ ++template <typename T1,typename T2> +struct mutable_pair +{ + typedef T1 first_type; + typedef T2 second_type; + + mutable_pair():first(T1()),second(T2()){} + mutable_pair(const T1& f,const T2& s):first(f),second(s){} + mutable_pair(const std::pair<T1,T2>& p):first(p.first),second(p.second){} + + T1 first; + mutable T2 second; +}; +
+and so the substitution rules are: +
+ ++ ++std::map<Key,T,Compare,Allocator> -> + multi_index_container< + Element, + indexed_by< + ordered_unique<member<Element,Key,&Element::first>,Compare> + >, + typename Allocator::template rebind<Element>::other + > + +std::multimap<Key,T,Compare,Allocator> -> + multi_index_container< + Element, + indexed_by< + ordered_non_unique<member<Element,Key,&Element::first>,Compare> + >, + typename Allocator::template rebind<Element>::other + > + +(with Element=mutable_pair<Key,T>) +
+If default values are considered, the rules take the form: +
+ ++ ++std::map<Key,T> -> + multi_index_container< + Element, + indexed_by<ordered_unique<member<Element,Key,&Element::first> > > + > + +std::multimap<Key,T> -> + multi_index_container< + Element, + indexed_by<ordered_non_unique<member<Element,Key,&Element::first> > > + > + +(with Element=mutable_pair<Key,T>) +
+Unlike as with standard sets, the interface of these multi_index_container
-simulated
+maps does not exactly conform to that of std::map
s and
+std::multimap
s. The most obvious difference is the lack of
+operator []
, either in read or write mode; this, however, can be
+simulated with appropriate use of find
and insert
.
+
+These simulations of standard associative containers with multi_index_container
+are comparable to the original constructs in terms of space and time efficiency.
+See the performance section for further details.
+
std::list
+Unlike the case of associative containers, simulating std::list
+in Boost.MultiIndex does not add any significant functionality, so the following
+is presented merely for completeness sake.
+
+Much as with standard maps, the main difficulty to overcome when simulating
+std::list
derives from the constant nature of elements of an
+multi_index_container
. Again, some sort of adaption class is needed, like
+for instance the following:
+
+ ++template <typename T> +struct mutable_value +{ + mutable_value(const T& t):t(t){} + operator T&()const{return t;} + +private: + mutable T t; +}; +
+which allows us to use the substitution rule: +
+ ++ ++std::list<T,Allocator> -> + multi_index_container< + Element, + indexed_by<sequenced<> >, + typename Allocator::template rebind<Element>::other + > + +(with Element=mutable_value<T>) +
+or, if the default value Allocator=std::allocator<T>
is used:
+
+ ++std::list<T> -> + multi_index_container<mutable_value<T>,indexed_by<sequenced<> > > +
multi_index_container
+Boost.MultiIndex provides a number of facilities intended to allow the analysis and
+synthesis of multi_index_container
instantiations by
+MPL metaprograms.
+
+Given a multi_index_container
instantiation, the following nested types are
+provided for compile-time inspection of the various types occurring in the
+definition of the multi_index_container
:
+
index_specifier_type_list
,index_type_list
,iterator_type_list
,const_iterator_type_list
.MPL Forward Sequence
with as many elements as indices
+comprise the multi_index_container
: for instance, the n
-nth
+element of iterator_type_list
is the same as
+nth_index_iterator<n>::type
.
+
+
+
+A subtle but important distinction exists between
+index_specifier_type_list
and index_type_list
:
+the former typelist holds the index specifiers
+with which the multi_index_container
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:
+
+ ++typedef multi_index_container< + int, + indexed_by< + ordered_unique<identity<int> >, + sequenced<> + > +> indexed_t; +
+indexed_t::index_specifier_type_list
is a type list with
+elements
+
+ ++ordered_unique<identity<int> > +sequenced<> +
+while indexed_t::index_type_list
holds the types
+
+ ++multi_index_container::nth_type<0>::type +multi_index_container::nth_type<1>::type +
+so the typelists are radically different. +
+ +
+Although typically indices are specified by means of the
+indexed_by
construct, actually any MPL sequence of
+index specifiers can be provided instead:
+
+ ++typedef mpl::vector<ordered_unique<identity<int> >,sequenced<> > index_list_t; + +typedef multi_index_container< + int, + index_list_t +> indexed_t; +
+This possibility enables the synthesis of instantiations of
+multi_index_container
through MPL metaprograms, as the following
+example shows:
+
+ ++// original multi_index_container instantiation +typedef multi_index_container< + int, + indexed_by< + ordered_unique<identity<int> > + > +> indexed_t1; + +// we take its index list and add an index +typedef boost::mpl::push_front< + indexed_t1::index_specifier_type_list, + sequenced<> +>::type index_list_t; + +// augmented multi_index_container +typedef multi_index_container< + int, + index_list_t +> indexed_t2; +
Revised May 7th 2004
+ +Copyright © 2003-2004 Joaquín M López Muñoz. +Use, modification, and distribution are subject to the Boost Software +License, Version 1.0. (See accompanying file +LICENSE_1_0.txt or copy at +www.boost.org/LICENSE_1_0.txt) +
+ + + diff --git a/doc/compiler_specifics.html b/doc/compiler_specifics.html new file mode 100644 index 0000000..bbfc475 --- /dev/null +++ b/doc/compiler_specifics.html @@ -0,0 +1,314 @@ + + + + + ++Boost.MultiIndex has been tried in different compilers, with +various degrees of success. We list the limitations encountered, +along with suitable workarounds when available. Up to date information +on compatibility of Boost.MultiIndex with several compilers can +be found at the +Boost Compiler Status Summary. +
+ ++Currently, Boost.MultiIndex cannot be used with BCB 6.4. The +number of problems encountered during the tests makes it unlikely that +future versions of the library can be made to work under +this compiler. +
+ ++No problems have been detected with this compiler. The tests were +performed under Cygwin 1.5.7. Most likely Boost.MultiIndex will work seamlessly +for GNU GCC 3.3 or later under any platform. +
+ +
+member
not supported,
+replace with
+member_offset
or
+use the cross-platform macro
+
+BOOST_MULTI_INDEX_MEMBER
.
+
+Altough Koenig lookup seems to be officially supported by this compiler,
+some issues have arisen seemingly due to bugs related to this facility.
+In these cases you might need to explicitly qualify global names with
+::boost::multi_index
.
+
+No problems have been detected with this compiler. +
+ ++No problems have been detected with this compiler. +
+ + +
+member
not supported,
+replace with
+member_offset
or
+use the cross-platform macro
+
+BOOST_MULTI_INDEX_MEMBER
.
+
+const_mem_fun
not
+supported, replace with
+
+const_mem_fun_explicit
+or use the cross-platform macro
+
+BOOST_MULTI_INDEX_CONST_MEM_FUN
.
+
+mem_fun
is not
+supported, replace with
+
+mem_fun_explicit
or
+use the cross-platform macro
+
+BOOST_MULTI_INDEX_MEM_FUN
.
+
+No support for index retrieval +and projection +nested types and member functions: +
nth_index
,index
,nth_index_iterator
,nth_index_const_iterator
,index_iterator
,index_const_iterator
,get
,project
.::boost::multi_index
.
+
+
+
+The lack of partial template specialization support in MSVC++ 6.0
+results in some inconveniences when using composite_key
that
+can be remedied as explained in
+"composite_key
+in compilers without partial template specialization" on the advanced
+topics section.
+
+MSVC++ 6.0 presents serious limitations for the maximum length of
+symbol names generated by the compiler, which might result in the
+linker error
+LNK1179:
+invalid or corrupt file: duplicate comdat
+comdat
. To overcome this problem, you can restrict the maximum
+number of elements accepted by
+indexed_by
,
+tag
and
+composite_key
+by globally setting the values of the macros
+
BOOST_MULTI_INDEX_LIMIT_INDEXED_BY_SIZE
+ (default in MSVC++ 6.0: 5),BOOST_MULTI_INDEX_LIMIT_TAG_SIZE
+ (default in MSVC++ 6.0: 3),BOOST_MULTI_INDEX_LIMIT_COMPOSITE_KEY_SIZE
+ (default in MSVC++ 6.0: 5).
+Under some circumstances, the compiler emits the error
+
+C2587
: '_U' : illegal use of local variable as
+default parameter
, inside the MSVC internal header
+<xlocnum>
.
+This problem is a recurrent bug of the compiler, and has been reported in
+other unrelated libraries, like the
+Boost Graph Library,
+Boost.MultiArray,
+Boost.Regex,
+CGAL and
+MySQL++.
+The error is triggered, though not in a systematic manner, by the use
+of multi_index_container
iterator constructor. Two workarounds exist:
+the first consists of avoiding this constructor and replacing
+code like:
+
+ ++multi_index_container<...> s(c.begin(),c.end()); +
+with equivalent operations: +
+ ++ ++multi_index_container<...> s; +s.insert(c.begin(),c.end()); +
+The second workaround has not been confirmed by the author, but it is given
+on the Internet in connection with this error appearing in other libraries.
+Replace line 84 of <xlocnum>
+
+
+ ++ #define _VIRTUAL virtual +
+with the following: +
+ ++ + ++ #define _VIRTUAL +
+Warning: it is not known whether this
+replacement can result in unexpected side effects in code implicitly
+using <xlocnum>
.
+
+In general, the extensive use of templates by Boost.MultiIndex puts this compiler +under severe stress, so that several internal limitations may be reached. +The following measures can help alleviate these problems: +
/Zm
(Specify Memory Allocation Limit)
+ to increase the amount of memory available for compilation. Usual values for
+ this option range from 300 to 800./ZI
(Program Database for
+ Edit and Continue) to a less demanding type of debugging information
+ (/Zi
, /Z7
or Zd
.)C1055
: compiler limit : out of keys
, try
+ disabling the option /Gm
(Enable Minimal Rebuild.) In these
+ cases, it is also beneficial to split the project into smaller
+ subprojects.+Boost.MultiIndex works for this configuration. The same limitations apply as +in MSVC++ 6.0 with its original Dinkumware standard library. +
+ +
+Problems have been reported when compiling the library with the /Gm
+option (Enable Minimal Rebuild.) Seemingly, this is due to an
+internal defect of the compiler (see for instance
+
+this mention of a similar issue in the Boost Users mailing list.)
+If /Gm
is turned off, Boost.MultiIndex compiles and runs
+without further problems.
+
Revised May 7th 2004
+ +Copyright © 2003-2004 Joaquín M López Muñoz. +Use, modification, and distribution are subject to the Boost Software +License, Version 1.0. (See accompanying file +LICENSE_1_0.txt or copy at +www.boost.org/LICENSE_1_0.txt) +
+ + + diff --git a/doc/examples.html b/doc/examples.html new file mode 100644 index 0000000..87e581b --- /dev/null +++ b/doc/examples.html @@ -0,0 +1,319 @@ + + + + + +multi_index_container
s
+ with ctor_args_list
+See source code. +
+ +
+Basic program showing the multi-indexing capabilities of Boost.MultiIndex
+with an admittedly boring set of employee
records.
+
+See source code. +
+ +
+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. This has some similarity with the concept of
+calculated keys supported by some relational database engines.
+The example shows how to use the predefined const_mem_fun
+key extractor to deal with this situation.
+
+Keys based on member functions usually will not be actual references,
+but rather the temporary values resulting from the invocation of the
+member function used. This implies that modify_key
cannot be
+applied to this type of extractors, which is a perfectly logical
+constraint anyway.
+
multi_index_container
s
+with ctor_args_list
+See source code. +
+ +
+We show a practical example of usage of multi_index_container::ctor_arg_list
,
+whose definition and purpose are explained in the
+Advanced topics section. The
+program groups a sorted collection of numbers based on identification through
+modulo arithmetics, by which x
and y
are equivalent
+if (x%n)==(y%n)
, for some fixed n
.
+
+See source code. +
+ +
+This example shows how to construct a bidirectional map with
+multi_index_container
. By a bidirectional map we mean
+a container of elements of std::pair<const FromType,const ToType>
+such that no two elements exists with the same first
+or second
value (std::map
only
+guarantees uniqueness of the first member). Fast lookup is provided
+for both keys. The program features a tiny Spanish-English
+dictionary with online query of words in both languages.
+
+See source code. +
+ +
+The combination of a sequenced index with an index of type ordered_non_unique
+yields a list
-like structure with fast lookup capabilities. The
+example performs some operations on a given text, like word counting and
+selective deletion of some words.
+
+See source code. +
+ +
+This program illustrates some advanced techniques that can be applied
+for complex data structures using multi_index_container
.
+Consider a car_model
class for storing information
+about automobiles. On a fist approach, car_model
can
+be defined as:
+
+ ++struct car_model +{ + std::string model; + std:string manufacturer; + int price; +}; +
+This definition has a design flaw that any reader acquainted with
+relational databases can easily spot: The manufacturer
+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
+multi_index_container
and store pointers to these in
+car_model
:
+
+ ++struct car_manufacturer +{ + std::string name; +}; + +struct car_model +{ + std::string model; + car_manufacturer* manufacturer; + int price; +}; +
+Although predefined Boost.MultiIndex key extractors can handle many +situations involving pointers (see +advanced features +of Boost.MultiIndex key extractors in the Advanced topics section), this case +is complex enough that a suitable key extractor has to be defined. The following +utility cascades two key extractors: +
+ ++ ++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; +}; +
+so that access from a car_model
to the name
field
+of its associated car_manufacturer
can be accomplished with
+
+ ++key_from_key< + member<car_manufacturer,const std::string,&car_manufacturer::name>, + member<car_model,const car_manufacturer *,car_model::manufacturer> +> +
+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: +
equal_range
,
+ multi_index_container
sorted
+ by price,
+ lower_bound
and
+ upper_bound
;
+lower_bound
and upper_bound
,
+ multi_index_container
sorted
+ by manufacturer,
+ equal_range
.
+multi_index_container
.
+In order to avoid object copying, appropriate view types
+are defined with multi_index_container
s having as elements
+pointers to car_model
s instead of actual objects.
+These views have to be supplemented with appropriate
+dereferencing key extractors.
+
+
++See source code. +
+ +
+Boost.MultiIndex
+composite_key
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:
+
+ ++struct file_entry +{ + std::string name; + unsigned size; + bool is_dir; // true if the entry is a directory + const file_entry* dir; // directory this entry belongs in +}; +
+Entries are kept in a multi_index_container
maintaining two indices
+with composite keys:
+
ls
. The shell simulation only has three
+commands:
+cd [.|..|<directory>]
ls [-s]
(-s
orders the output by size)mkdir <directory>
+The reader is challenged to add more functionality to the program (for
+instance, implementation of the cp
command and handling of
+absolute paths.)
+
Revised May 7th 2004
+ +Copyright © 2003-2004 Joaquín M López Muñoz. +Use, modification, and distribution are subject to the Boost Software +License, Version 1.0. (See accompanying file +LICENSE_1_0.txt or copy at +www.boost.org/LICENSE_1_0.txt) +
+ + + diff --git a/doc/future_work.html b/doc/future_work.html new file mode 100644 index 0000000..dc709e3 --- /dev/null +++ b/doc/future_work.html @@ -0,0 +1,273 @@ + + + + + +
+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 multi_index_container
.
+
+Several STL implementations feature hashed sets as a natural
+counterpart to std::set
and std::multiset
.
+multi_index_container
can also benefit from the inclusion of hashed
+indices. As the exact details of the interfaces of hashed sets differ among
+library vendors, a good starting point seems Matt Austern's paper
+A
+Proposal to Add Hash Tables to the Standard Library (revision 4), which
+has been submitted for acceptance into the next revision of the
+C++ standard.
+
+Ordered indices are implemented using red-black trees; these trees
+can be augmented with additional information to obtain a type
+of data structure called
+order-statistics
+trees, allowing for logarithmic search of the n-th element. It
+has been proposed that order-statistics trees be used to devise a new type of
+ranked indices that support operator[]
while retaining
+the functionality of ordered indices.
+
+Notifying indices 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 +Boost.Signals +library. This functionality can have applications for: +
+The following is a sketch of a possible realization of notifying +indices: +
+ ++ ++struct insert_log +{ + void operator()(int x) + { + std::clog<<"insert: "<<x<<std::endl; + } +}; + +int main() +{ + typedef multi_index_container< + int, + indexed_by< + notifying<ordered_unique<identity<int> > >, // notifying index + ordered_non_unique<identity<int> > + > + > indexed_t; + + indexed_t t; + + // on_insert is the signal associated to insertions + t.on_insert.connect(insert_log()); + + t.insert(0); + t.insert(1); + + return 0; +} + +// output: +// insert: 0 +// insert: 1 +
+The notifying indices functionality described above exploits a powerful +design pattern based on index adaptors, 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 constraints, 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: +
+ ++ ++struct is_even +{ + bool operator()(int x)const{return x%2==0;} +}; + +typedef multi_index_container< + int, + indexed_by< + constrained<ordered_unique<identity<int> >,is_even> + > +> indexed_t; +
+The mechanisms by which Boost.MultiIndex orchestrates the
+operations of the indices held by a multi_index_container
are
+simple enough to make them worth documenting so that the (bold)
+user can write implementations for her own indices.
+
+Example 4 in the examples section
+features a bidirectional map, implemented as an
+multi_index_container
with two unique ordered indices. This particular
+structure is deemed important enough as to provide it as a separate
+class template, relying internally in multi_index_container
. As
+feedback is collected from the users of Boost.MultiIndex, other singular
+instantiations of multi_index_container
might be encapsulated
+to form a component library of ready to use containers.
+
+multi_index_container
is rich enough to provide the basis
+for implementation of indexed maps, 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 multi_index_container
.
+
+The main challenge in writing an indexed map lies in the design of a
+reasonable interface that resembles that of std::map
as
+much as possible. There seem to be fundamental difficulties in extending
+the syntax of a std::map
to multiple keys. For one example,
+consider the situation:
+
+ ++indexed_map<int,string,double> m; +// keys are int and string, double is the mapped to value + +... + +cout<<m[0]<<endl; // OK +cout<<m["zero"]<<endl; // OK +m[1]=1.0; // !! +
+In the last sentence of the example, the user has no way of
+providing the string
key mapping to the same value
+as m[1]
. This and similar problems have to be devoted
+a careful study when designing the interface of a potential
+indexed map.
+
+Once Robert Ramey's
+serialization library gets accepted into Boost, support for
+archiving/retrieving multi_index_container
s should be added.
+
+Andrei Alexandrescu introduced a technique for simulating move
+constructors called Mojo (see his article in C/C++ User Journal
+
+"Generic<Programming>: Move Constructors".) Move semantics
+alleviates the computational load involved in the creation and copying
+of temporary objects, specially for heavy classes as
+multi_index_container
s are. David Abrahams and Gary Powell provide
+an alternative implementation of move semantics in their paper
+
+"Clarification of Initialization of Class Objects by rvalues" for
+the C++ Evolution Working Group.
+
+Adding move semantics to multi_index_container
is particularly
+beneficial when the container is used as an internal building block in other
+libraries (vg. relational database frameworks), enabling the efficient
+development of functions returning multi_index_container
s. Without support
+for move semantics, this scheme is impractical and less elegant syntaxes
+should be resorted to.
+
Revised May 7th 2004
+ +Copyright © 2003-2004 Joaquín M López Muñoz. +Use, modification, and distribution are subject to the Boost Software +License, Version 1.0. (See accompanying file +LICENSE_1_0.txt or copy at +www.boost.org/LICENSE_1_0.txt) +
+ + + diff --git a/doc/index.html b/doc/index.html new file mode 100644 index 0000000..5147aa6 --- /dev/null +++ b/doc/index.html @@ -0,0 +1,74 @@ + + + + + +
+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.
+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.
+
+Boost.MultiIndex features additional functionalities, like subobject searching,
+range querying and in-place updating of elements, which make it a convenient replacement
+for std::set
and set::multiset
even when no multi-indexing
+capabilities are needed.
+
Revised May 7th 2004
+ +Copyright © 2003-2004 Joaquín M López Muñoz. +Use, modification, and distribution are subject to the Boost Software +License, Version 1.0. (See accompanying file +LICENSE_1_0.txt or copy at +www.boost.org/LICENSE_1_0.txt) +
+ + + diff --git a/doc/lopez.jpg b/doc/lopez.jpg new file mode 100644 index 0000000..ac37b4a Binary files /dev/null and b/doc/lopez.jpg differ diff --git a/doc/multi_index_cont_example.png b/doc/multi_index_cont_example.png new file mode 100644 index 0000000..120cfdd Binary files /dev/null and b/doc/multi_index_cont_example.png differ diff --git a/doc/next.gif b/doc/next.gif new file mode 100644 index 0000000..d6c18a5 Binary files /dev/null and b/doc/next.gif differ diff --git a/doc/perf_1o.png b/doc/perf_1o.png new file mode 100644 index 0000000..061c8ec Binary files /dev/null and b/doc/perf_1o.png differ diff --git a/doc/perf_1o1s.png b/doc/perf_1o1s.png new file mode 100644 index 0000000..4408092 Binary files /dev/null and b/doc/perf_1o1s.png differ diff --git a/doc/perf_1s.png b/doc/perf_1s.png new file mode 100644 index 0000000..d76c2bb Binary files /dev/null and b/doc/perf_1s.png differ diff --git a/doc/perf_2o.png b/doc/perf_2o.png new file mode 100644 index 0000000..eeb820b Binary files /dev/null and b/doc/perf_2o.png differ diff --git a/doc/perf_2o1s.png b/doc/perf_2o1s.png new file mode 100644 index 0000000..e25371f Binary files /dev/null and b/doc/perf_2o1s.png differ diff --git a/doc/perf_3o.png b/doc/perf_3o.png new file mode 100644 index 0000000..198d363 Binary files /dev/null and b/doc/perf_3o.png differ diff --git a/doc/performance.html b/doc/performance.html new file mode 100644 index 0000000..6ad7dbe --- /dev/null +++ b/doc/performance.html @@ -0,0 +1,724 @@ + + + + + +multi_index_container
+Boost.MultiIndex helps the programmer to avoid the manual construction of cumbersome
+compositions of containers when multiindexing 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 multi_index_container
s with two or more indices, the running time
+can be reduced to half as long as with manual simulations involving several
+STL containers.
+
multi_index_container
+The section of simulation
+of standard containers with multi_index_container
shows the equivalence
+between single-index multi_index_container
s and some STL containers. Let us now
+concentrate on the problem of simulating a multi_index_container
with two
+or more indices with a suitable combination of standard containers.
+
+Consider the following instantiation of multi_index_container
:
+
+ ++typedef multi_index_container< + int, + indexed_by< + ordered_unique<identity<int> >, + ordered_non_unique<identity<int>, std::greater >, + > +> indexed_t; +
+indexed_t
maintains two internal indices on elements of type
+int
. In order to simulate this data structure resorting only to
+standard STL containers, one can use on a first approach the following types:
+
+ ++// 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; +}; + +typedef std::set<int> manual_t1; // equivalent to indexed_t's index #0 +typedef std::multiset< + const int*, + it_compare< + const int*, + std::greater<int> + > +> manual_t2; // equivalent to indexed_t's index #1 +
+where manual_t1
is the "base" container that holds
+the actual elements, and manual_t2
stores pointers to
+elements of manual_t1
. This scheme turns out to be quite
+inefficient, though: while insertion into the data structure is simple enough:
+
+ +deletion, on the other hand, necessitates a logarithmic search, whereas ++manual_t1 c1; +manual_t2 c2; + +// insert the element 5 +manual_t1::iterator=c1.insert(5).first; +c2.insert(&*t1); +
indexed_t
deletes in constant time:
+
++ ++// remove the element pointed to by it2 +manual_t2::iterator it2=...; +c1.erase(*it2); // watch out! performs in logarithmic time +c2.erase(it1); +
+The right approach consists of feeding the second container not with
+raw pointers, but with elements of type manual_t1::iterator
:
+
+ ++typedef std::set<int> manual_t1; // equivalent to indexed_t's index #0 +typedef std::multiset< + manual_t1::iterator, + it_compare< + manual_t1::iterator, + std::greater<int> + > +> manual_t2; // equivalent to indexed_t's index #1 +
+Now, insertion and deletion can be performed with complexity bounds
+equivalent to those of indexed_t
:
+
+ ++manual_t1 c1; +manual_t2 c2; + +// insert the element 5 +manual_t1::iterator=c1.insert(5).first; +c2.insert(t1); + +// remove the element pointed to by it2 +manual_t2::iterator it2=...; +c1.erase(*it2); // OK: constant time +c2.erase(it1); +
+The construction can be extended in a straightworward manner to
+handle more than two indices. In what follows, we will compare
+instantiations of multi_index_container
against this sort of
+manual simulations.
+
+The gain in space consumption of multi_index_container
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 multi_index_container
.)
+
+Nodes of a multi_index_container
with N indices hold the value
+of the element plus N headers containing linking information for
+each index. Thus the node size is
+
+SI = e + h0 + ··· + +hN-1, where+ +
+e = size of the element,
+hi = size of the i-th header. +
+On the other hand, the manual simulation allocates N 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. Suming all contributions, +the space allocated per element in a manual simulation is +
+ ++SM = (e + h0) + +(p + h1) + ··· + +(p + hN-1) = +SI + (N-1)p, where+ +
+p = size of a pointer.
+
+The relative amount of memory taken up by multi_index_container
+with respect to its manual simulation is just
+SI / SM, which can be expressed
+then as:
+
+SI / SM = +SI / (SI + (N-1)p). ++ +
+The formula shows that multi_index_container
is more efficient
+with regard to memory consumption as the number of indices grow.
+
+These considerations have overlooked an aspect of the greatest practical
+importance: the fact that multi_index_container
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.
+
+From the point of view of computational complexity (i.e. big-O
+characterization), multi_index_container
and its corresponding manual
+simulations are equivalent: inserting an element into
+a multi_index_container
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
+multi_index_container
s with two or more indices.
+
In the special case of multi_index_container
s with only one index,
+the best we can hope for is equal performance: the tests show that the
+performance degradation in this particular situation ranges from negligible
+to small, depending on the compiler used.
+
+See source code used for measurements. +
+In order to assess the efficiency of multi_index_container
, the following
+basic algorithm
+
+ ++multi_index_container<...> c; +for(int i=0;i<n;++i)c.insert(i); +for(iterator it=c.begin();it!=c.end();)c.erase(it++); +
+has been measured for different instantiations of multi_index_container
+at values of n 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 following compilers have been used:
+
+The relative memory consumption (i.e. the amount of memory allocated
+by a multi_index_container
with respect to its manual simulation)
+is determined by dividing the size of a multi_index_container
node
+by the sum of node sizes of all the containers integrating the
+simulating data structure.
+
+The following instantiation of multi_index_container
was tested:
+
+ ++multi_index_container< + int, + indexed_by< + ordered_unique<identity<int> > + > +> +
+which is functionally equivalent to std::set<int>
.
+
+
GCC 3.1.1 | +ICC 7.1 | +MSVC 6.5 | +
---|---|---|
100% | +100% | +100% | +
multi_index_container
with 1
+ordered index.
+
+
+
+The figures confirm that in this case multi_index_container
nodes are the
+same size than those of its std::set
counterpart.
+
+
+Fig. 1: Performance of multi_index_container
with 1 ordered index.
+
+As expected, multi_index_container
does perform in this case somewhat
+worse than std::set
. The degradation is within 10% for ICC and
+MSVC compilers, while in GCC peaks to 20%, which can be significative
+in certain applications. This latter result is presumably accounted for by
+a lower quality of the optimizing stage carried out by GCC.
+
+The following instantiation of multi_index_container
was tested:
+
+ ++multi_index_container< + int, + indexed_by< + sequenced<> + > +> +
+which is functionally equivalent to std::list<int>
.
+
+
GCC 3.1.1 | +ICC 7.1 | +MSVC 6.5 | +
---|---|---|
100% | +100% | +100% | +
multi_index_container
with 1
+sequenced index.
+
+
+
+The figures confirm that in this case multi_index_container
nodes are the
+same size than those of its std::list
counterpart.
+
+
+Fig. 2: Performance of multi_index_container
with 1 sequenced index.
+
+As in the former case, multi_index_container
does not attain the performance
+of its STL counterpart. Again, worst results are those of GCC, with a
+degradation of up to 20% , while ICC and MSVC do not exceed a mere 5%.
+
+The following instantiation of multi_index_container
was tested:
+
+ ++multi_index_container< + int, + indexed_by< + ordered_unique<identity<int> >, + ordered_non_unique<identity<int> > + > +> +
+
GCC 3.1.1 | +ICC 7.1 | +MSVC 6.5 | +
---|---|---|
90% | +90% | +90% | +
multi_index_container
with 2
+ordered indices.
+
+
++These results concinde with the theoretical formula for +SI=36 and p=4. +
+ +
+
+Fig. 3: Performance of multi_index_container
with 2 ordered indices.
+
+The experimental results confirm our hypothesis that multi_index_container
+provides an improvement on execution time by an approximately constant factor,
+which in this case ranges from 65% to 75% depending on the compiler.
+
+The following instantiation of multi_index_container
was tested:
+
+ ++multi_index_container< + int, + indexed_by< + ordered_unique<identity<int> >, + sequenced<> + > +> +
+
GCC 3.1.1 | +ICC 7.1 | +MSVC 6.5 | +
---|---|---|
87.5% | +87.5% | +87.5% | +
multi_index_container
with 1
+ordered index + 1 sequenced index.
+
+
++These results concinde with the theoretical formula for +SI=28 and p=4. +
+ +
+
+Fig. 4: Performance of multi_index_container
with 1 ordered index
++ 1 sequenced index.
+
+For n=103 and n=104, the results
+are in agreement with our theoretical analysis, showing a constant factor
+improvement of 60-75% with respect to the STL-based manual simulation.
+Curiously enough, this speedup gets even higher when
+n=105 for two of he compilers (35% for ICC,
+25% for MSVC.) In order to rule out spurious results, the tests
+have been run many times, yielding similar outcoumes. A tentative
+explanation of this unexpected behavior may point to a degradation in
+the execution time of the manual simulation, attributable to poor
+performance of the standard STL allocator in ICC and MSVC when dealing
+with many objects of diverse sizes (the manual simulation is comprised of
+an std::set
and a std::list
, which demand
+differently sized nodes.)
+
+The following instantiation of multi_index_container
was tested:
+
+ ++multi_index_container< + int, + indexed_by< + ordered_unique<identity<int> >, + ordered_non_unique<identity<int> >, + ordered_non_unique<identity<int> > + > +> +
+
GCC 3.1.1 | +ICC 7.1 | +MSVC 6.5 | +
---|---|---|
86.7% | +86.7% | +86.7% | +
multi_index_container
with 3
+ordered indices.
+
+
++These results concinde with the theoretical formula for +SI=52 and p=4. + +
+ +
+
+Fig. 5: Performance of multi_index_container
with 3 ordered indices.
+
+Execution time for this case is between 55% and 65% lower than achieved with +an STL-based manual simulation of the same data structure. +
+ +
+The following instantiation of multi_index_container
was tested:
+
+ ++multi_index_container< + int, + indexed_by< + ordered_unique<identity<int> >, + ordered_non_unique<identity<int> >, + sequenced<> + > +> +
+
GCC 3.1.1 | +ICC 7.1 | +MSVC 6.5 | +
---|---|---|
84.6% | +84.6% | +84.6% | +
multi_index_container
with 2
+ordered indices + 1 sequenced index.
+
+
++These results concinde with the theoretical formula for +SI=44 and p=4. +
+ +
+
+Fig. 6: Performance of multi_index_container
with 2 ordered indices
++ 1 sequenced index.
+
+In accordance to the expectations, execution time is improved by a fairly constant +factor, which ranges from 45% to 55%. +
+ +
+We have shown that multi_index_container
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.
+
+In the special case of replacing standard containers with single-indexed
+multi_index_container
s, the programmer should balance the benefits brought on
+by Boost.MultiIndex (subobject searching, in-place updating, etc.) against the
+resulting degradation in execution time. Depending on the compiler, this degradation
+can reach up to 20% of the original time.
+
Revised May 7th 2004
+ +Copyright © 2003-2004 Joaquín M López Muñoz. +Use, modification, and distribution are subject to the Boost Software +License, Version 1.0. (See accompanying file +LICENSE_1_0.txt or copy at +www.boost.org/LICENSE_1_0.txt) +
+ + + diff --git a/doc/prev.gif b/doc/prev.gif new file mode 100644 index 0000000..c35dfee Binary files /dev/null and b/doc/prev.gif differ diff --git a/doc/reference/index.html b/doc/reference/index.html new file mode 100644 index 0000000..227614c --- /dev/null +++ b/doc/reference/index.html @@ -0,0 +1,116 @@ + + + + + +multi_index_container
+The following dependencies among headers of Boost.MultiIndex hold: +
"boost/multi_index_container.hpp"
+ includes
+
+ "boost/multi_index/ordered_index.hpp"
includes
+
+ "boost/multi_index/sequenced_index.hpp"
includes
+
+ "boost/multi_index/key_extractors.hpp"
+ includes
+
+ "boost/multi_index_container.hpp"
,
+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
+
+"boost/multi_index/key_extractors.hpp"
.
+
+
++Boost.MultiIndex is a header-only library, requiring no linking with additional +object modules. +
+ +Revised May 7th 2004
+ +Copyright © 2003-2004 Joaquín M López Muñoz. +Use, modification, and distribution are subject to the Boost Software +License, Version 1.0. (See accompanying file +LICENSE_1_0.txt or copy at +www.boost.org/LICENSE_1_0.txt) +
+ + + diff --git a/doc/reference/indices.html b/doc/reference/indices.html new file mode 100644 index 0000000..e27da56 --- /dev/null +++ b/doc/reference/indices.html @@ -0,0 +1,328 @@ + + + + + +"boost/multi_index/indexed_by.hpp"
synopsis
+
+ "boost/multi_index/tag.hpp"
synopsis
+
+
+multi_index_container
instantiations comprise one or more indices
+specified at compile time. Each index allows read/write access to the elements
+contained in a definite manner. For instance,
+ordered indices
+provide a set-like interface to the elements, whereas
+sequenced indices mimic the functionality
+of std::list
.
+
+Indices are not isolated objects, and so cannot be constructed on their
+own. Rather they are embedded into a multi_index_container
as specified by
+means of an index specifier. The name of
+the index class implementation proper is never directly exposed to the user, who
+has only access to the associated index specifier.
+
+Insertion and erasing of elements are always performed through the
+appropriate interface of some index of the multi_index_container
;
+these operations, however, do have an impact on all other indices as
+well: for instance, insertion through a given index may fail because
+there exists another index which bans the operation in order to preserve
+its invariant (like uniqueness of elements.) This circumstance, rather
+than 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:
+
multi_index_container
are not mutable.
+To overcome this restriction, indices expose member functions
+for updating and modifying, which allow for the mutation of elements
+in a controlled fasion. Immutability of elements does not significantly
+impact the interface of ordered indices, as it is based upon that of
+std::set
and std:multiset
, and these containers
+also have non-mutable elements; but it may come as a surprise when dealing
+with sequenced indices, which are designed upon the functionality provided
+by std::list
.
+
+
+
+These global operations are not directly exposed to the user, but rather
+they are wrapped as appropriate by each index (for instance, ordered indices
+provide a set-like suite of insertion member functions, whereas sequenced
+indices do have push_back
and push_front
+operations.) Boost.MultiIndex poses no particular conditions on
+the interface of indices, save that they must model
+
+Container
(without the requirement of being
+
+Assignable
.)
+
+Some member functions of an index interface are implemented by
+global primitives from the list above. Complexity of these operations
+thus depends on all indices of a given multi_index_container
, not just
+the currently used index.
+
+In order to establish complexity estimates, an index is characterized +by its complexity signature, consisting of the following +associated functions on the number of elements: +
c(n)
: copying,
+ i(n)
: insertion,
+ h(n)
: hinted insertion,
+ d(n)
: deletion,
+ r(n)
: replacement,
+ m(n)
: modifying.
+multi_index_container
+with N
indices labelled 0
,...,N-1
+whose complexity signatures are
+(ci
,ii
,hi
,di
,ri
,mi
);
+the insertion of an element in such a set is then of complexity
+O(I0(n)+···+IN-1(n))
where n
+is the number of elements. To abbreviate notation, we adopt the
+following definitions:
+C(n)=c0(n)+···+cN-1(n)
,I(n)=i0(n)+···+iN-1(n)
,H(n)=h0(n)+···+hN-1(n)
,D(n)=d0(n)+···+dN-1(n)
,R(n)=r0(n)+···+rN-1(n)
,M(n)=m0(n)+···+mN-1(n)
.multi_index_container
with two ordered indices,
+for which i(n)=log(n)
, and a sequenced index with i(n)=1
+(constant time insertion). Insertion of an element into this multi_index_container
+is then of complexity
+
+O(I(n))=O(2*log(n)+1)=O(log(n))
.
+
+
+
+
+Index specifiers are passed as instantiation arguments to
+multi_index_container
and provide the information needed to incorporate
+the corresponding indices. Future releases of Boost.MultiIndex may allow for
+specification of user-defined indices. Meanwhile, the requirements for an index
+specifier remain implementation defined. Currently, Boost.MultiIndex provides the
+index specifiers
+ordered_unique
and
+ordered_non_unique
for
+ordered indices and
+sequenced
for
+sequenced indices.
+
"boost/multi_index/indexed_by.hpp"
synopsis+ ++namespace boost{ + +namespace multi_index{ + +template<typename T0,...,typename Tn> +struct indexed_by; + +} // namespace boost::multi_index + +} // namespace boost +
indexed_by
+indexed_by
is a
+
+MPL Forward Sequence
meant to be used to specify a
+compile-time list of indices as the IndexSpecifierList
of
+multi_index_container
.
+
+ ++template<typename T0,...,typename Tn> +struct indexed_by; +
+Each user-provided element of indexed_list
must be an index
+specifier. At least an element must be provided. The maximum number of elements
+of an indexed_by
sequence is implementation defined.
+
+Tags are just conventional types used as mnemonics for indices of an
+multi_index_container
, as for instance in member function get
.
+Each index can have none, one or more tags associated. The way tags are assigned
+to a given index is dependent on the particular index specifier. However,
+for convenience all indices of Boost.MultiIndex support tagging through the
+class template tag
.
+
"boost/multi_index/tag.hpp"
synopsis+ ++namespace boost{ + +namespace multi_index{ + +template<typename T0,...,typename Tn> +struct tag; + +} // namespace boost::multi_index + +} // namespace boost +
tag
+tag
is a typelist construct used to specify a compile-time
+sequence of tags to be assigned to an index in instantiation time.
+
+ ++template<typename T0,...,typename Tn> +struct tag; +
+Elements of tag
can be any type, though the user is expected
+to provide classes with mnemonic names. Duplicate elements are not allowed.
+The maximum number of elements of a tag
instantiation is
+implementation defined.
+
+Indices of this type are organized around keys obtained from the +elements, as described in the key extraction +reference. +
+
Revised May 7th 2004
+ +Copyright © 2003-2004 Joaquín M López Muñoz. +Use, modification, and distribution are subject to the Boost Software +License, Version 1.0. (See accompanying file +LICENSE_1_0.txt or copy at +www.boost.org/LICENSE_1_0.txt) +
+ + + diff --git a/doc/reference/key_extraction.html b/doc/reference/key_extraction.html new file mode 100644 index 0000000..01560ec --- /dev/null +++ b/doc/reference/key_extraction.html @@ -0,0 +1,1505 @@ + + + + + +"boost/multi_index/key_extractors.hpp"
synopsis
+ "boost/multi_index/identity.hpp"
synopsis
+
+ "boost/multi_index/member.hpp"
synopsis
+
+ "boost/multi_index/mem_fun.hpp"
synopsis
+
+ "boost/multi_index/composite_key.hpp"
synopsis
+ composite_key
composite_key_result
composite_key_compare
composite_key_result_less
composite_key_result_greater
std::less
for composite_key
resultsstd::greater
for composite_key
results
+Key extraction classes are used by ordered indices to
+obtain the sorting keys from the elements of a multi_index_container
.
+An Assignable
+class KeyFromValue
is said to be a key extractor from a
+type T
if
+
KeyFromValue::result_type
is defined,k1(ca)
is defined and returns a value convertible
+ to const KeyFromValue::result_type&
,k2
is a copy of k1
, k1(ca)
is the
+ same value as k2(ca)
,k1
, k2
of type const KeyFromValue
,
+and ca
of type const Type&
.
+
+
+
+Additionally, KeyFromValue
is a read/write key extractor
+if the following extra conditions are met:
+
k1(a)
is defined and returns a value convertible
+ to KeyFromValue::result_type&
,const_cast<const KeyFromValue::result_type&>(k1(a))
+ is the same value as
+ k1(const_cast<const Type&>(a))
,k1
of type const KeyFromValue
and
+a
of type Type&
.
+
+
++Boost.MultiIndex provides five general-purpose key extractors: +
identity
,member
,const_mem_fun
andmem_fun
,composite_key
,member_offset
,const_mem_fun_explicit
andmem_fun_explicit
,
+The key extractors provided by Boost.MultiIndex are templatized according
+to the type Type
and serve to extract keys not only from objects
+of type Type
, but also from reference wrappers provided by
+Boost.Ref and from chained pointers
+to Type
(or to reference wrappers of Type
): a chained pointer
+is any type P
such that, for an object p
of type
+const P
+
*x
yields an object of type Type&
or
+ boost::reference_wrapper<Type>
, OR*x
yields a chained pointer to Type&
,Type&
or
+boost::reference_wrapper<Type>
.
++ +
"boost/multi_index/key_extractors.hpp"
synopsis
++ ++#include <boost/multi_index/identity.hpp> +#include <boost/multi_index/member.hpp> +#include <boost/multi_index/mem_fun.hpp> +#include <boost/multi_index/composite_key.hpp> +
+This header includes all the key extractors provided by Boost.MultiIndex. +
+ +"boost/multi_index/identity.hpp"
synopsis+ ++namespace boost{ + +namespace multi_index{ + +template<typename T> struct identity; + +} // namespace boost::multi_index + +} // namespace boost +
identity
+identity
is a Key Extractor
+that acts as a do-nothing identity functor.
+
+ ++template<typename Type> +struct identity +{ + typedef Type result_type; + + template<typename ChainedPtr> Type& operator()(const ChainedPtr& x)const; + const Type& operator()(const Type& x)const; + Type& operator()(Type& x)const; // only provided if Type is non-const + + // only provided if Type is non-const + const Type& operator()(const reference_wrapper<const Type>& x)const; + + // only provided if Type is const + Type& operator()( + const reference_wrapper<typename remove_const<Type>::type>& x)const; + + Type& operator()(const reference_wrapper<Type>& x)const; +}; +
+identity<Type>
is a model of:
+
Key Extractor
+ from Type
,Key Extractor
+ from reference_wrapper<const Type>
,Key Extractor
+ from reference_wrapper<Type>
,Key Extractor
+ from any chained pointer to
+ const Type
.Key Extractor
+ from any chained pointer
+ to Type
.identity
memberstemplate<typename ChainedPtr> Type& operator()(const ChainedPtr& x)const;
+
++Requires:+ +ChainedPtr
is a chained pointer +type toType
.
+Returns: a reference to the object chained-pointed to byx
. +
const Type& operator()(const Type&x)const;
+
+
+Returns: x
.
+
+
+Type& operator()(Type &x)const;
+
+
+Returns: x
.
+
+
+const Type& operator()(const reference_wrapper<const Type>& x)const;
+
+Returns: x.get()
.
+
+
+Type& operator()(const reference_wrapper<typename remove_const<Type>::type>& x)const;
+
+Returns: x.get()
.
+
+
+Type& operator()(const reference_wrapper<Type>& x)const;
+
+Returns: x.get()
.
+
+
+
+"boost/multi_index/member.hpp"
synopsis+ ++namespace boost{ + +namespace multi_index{ + +template<class Class,typename Type,Type Class::*PtrToMember> +struct member; + +template<class Class,typename Type,std::size_t OffsetOfMember> +struct member_offset; + +#define BOOST_MULTI_INDEX_MEMBER(Class,Type,MemberName) implementation defined + +} // namespace boost::multi_index + +} // namespace boost +
member
+member
is a Key Extractor
+aimed at accessing a given member of a class.
+
+ ++template<class Class,typename Type,Type Class::*PtrToMember> +struct member +{ + typedef Type result_type; + + template<typename ChainedPtr> Type& operator()(const ChainedPtr& x)const; + const Type& operator()(const Class& x)const; + Type& operator()(Class& x)const; // only provided if Type is non-const + const Type& operator()(const reference_wrapper<const Class>& x)const; + Type& operator()(const reference_wrapper<Class>& x)const; +}; +
+The PtrToMember
template argument specifies the particular
+Type Class::*
pointer to the member to be extracted.
+member<Class,Type,PtrToMember>
is a model of:
+
Key Extractor
+ from Class
if Type
is non-const
,Key Extractor
+ from reference_wrapper<const Class>
,Key Extractor
+ from reference_wrapper<Class>
,Key Extractor
+ from any chained pointer
+ to const Class
,Key Extractor
+ from any chained pointer
+ to Class
.member
memberstemplate<typename ChainedPtr> Type& operator()(const ChainedPtr& x)const;
+
++Requires:+ +ChainedPtr
is a chained pointer +type toType
.
+Returns: a reference to the object chained-pointed to byx
. +
const Type& operator()(const Class&x)const;
+
+
+Returns: x.*PtrToMember
.
+
+
+Type& operator()(const Class&x);
+
+
+Returns: x.*PtrToMember
.
+
+
+const Type& operator()(const reference_wrapper<const Class>& x)const;
+
+
+Returns: x.get().*PtrToMember
.
+
+
+Type& operator()(const reference_wrapper<Class>& x)const;
+
+
+Returns: x.get().*PtrToMember
.
+
+
+member_offset
+Some compilers do not properly support pointers to members as non-type +template arguments. The following have been confirmed to have bugs in +this respect: +
member_offset
provides an
+alternative to member
accepting offsets
+instead of pointers to members. Please note that the use of
+offsetof
on non-POD types is forbidden by the standard;
+luckily enough, most compilers accept it nevertheless, so
+member_offset
serves as a workaround for most practical purposes.
+
+
++ ++template<class Class,typename Type,Type Class::*PtrToMember> +struct member_offset +{ + typedef Type result_type; + + template<typename ChainedPtr> Type& operator()(const ChainedPtr& x)const; + const Type& operator()(const Class& x)const; + Type& operator()(Class& x)const; // only provided if Type is non-const + const Type& operator()(const reference_wrapper<const Class>& x)const; + Type& operator()(const reference_wrapper<Class>& x)const; +}; +
As an example of use, given the class
+ ++ ++class A +{ + int x; +} +
+the instantiation member<A,int,&A::x>
can be simulated then
+as member_offset<A,int,offsetof(A,x)>
.
+
BOOST_MULTI_INDEX_MEMBER
+ ++BOOST_MULTI_INDEX_MEMBER(Class,Type,MemberName) +
+This macro is provided as an aid for using member
and
+member_offset
when writing cross-platform code. In the usual cases,
+it expands to
+
+ ++::boost::multi_index::member<Class,Type,&Class::MemberName> +
+but it resolves to +
+ ++ ++::boost::multi_index::member_offset<Class,Type,offsetof(Class,MemberName)> +
+for the following compilers: +
BOOST_NO_POINTER_TO_MEMBER_TEMPLATE_PARAMETERS
+is defined.
+
+
+"boost/multi_index/mem_fun.hpp"
synopsis+ ++namespace boost{ + +namespace multi_index{ + +template<class Class,typename Type,Type (Class::*PtrToMemberFunction)()const> +struct const_mem_fun; + +template<class Class,typename Type,Type (Class::*PtrToMemberFunction)()> +struct mem_fun; + +template< + class Class,typename Type, + typename PtrToMemberFunctionType,PtrToMemberFunctionType PtrToMemberFunction +> +struct const_mem_fun_explicit; + +template< + class Class,typename Type, + typename PtrToMemberFunctionType,PtrToMemberFunctionType PtrToMemberFunction +> +struct mem_fun_explicit; + +#define BOOST_MULTI_INDEX_CONST_MEM_FUN(Class,Type,MemberFunName) \ +implementation defined +#define BOOST_MULTI_INDEX_MEM_FUN(Class,Type,MemberFunName) \ +implementation defined + +} // namespace boost::multi_index + +} // namespace boost +
const_mem_fun
+const_mem_fun
is a Key Extractor
+returning as key the result of invoking a given constant member function of a class.
+
+ ++template<class Class,typename Type,Type (Class::*PtrToMemberFunction)()const> +struct const_mem_fun +{ + typedef typename remove_reference<Type>::type result_type; + + template<typename ChainedPtr> Type operator()(const ChainedPtr& x)const; + Type operator()(const Class& x)const; + Type operator()(const reference_wrapper<const Class>& x)const; + Type operator()(const reference_wrapper<Class>& x)const; +}; +
+The PtrToMemberFunction
template argument specifies the particular
+Type (Class::*PtrToMemberFunction)()const
pointer to the the constant
+member function used in the extraction.
+const_mem_fun<Class,Type,PtrToMemberFunction>
is a model of:
+
Key Extractor
+ from Class
,Key Extractor
+ from reference_wrapper<const Class>
,Key Extractor
+ from reference_wrapper<Class>
,Key Extractor
+ from any chained pointer
+ to const Class
,Key Extractor
+ from any chained pointer
+ to Class
.const_mem_fun
memberstemplate<typename ChainedPtr> Type operator()(const ChainedPtr& x)const;
+
++Requires:+ +ChainedPtr
is a chained pointer +type toType
.
+Returns:(y.*PtrToMemberFunction)()
, wherey
is the +object chained-pointed to byx
. +
Type operator()(const Class& x)const;
+
+
+Returns: (x.*PtrToMemberFunction)()
.
+
+
+Type operator()(const reference_wrapper<const Class>& x)const;
+
+
+Returns: (x.get().*PtrToMemberFunction)()
.
+
+
+Type operator()(const reference_wrapper<Class>& x)const;
+
+
+Returns: (x.get().*PtrToMemberFunction)()
.
+
+
+mem_fun
+mem_fun
is a Key Extractor
+returning as key the result of invoking a given member function of a class.
+
+ ++template<class Class,typename Type,Type (Class::*PtrToMemberFunction)()> +struct mem_fun +{ + typedef typename remove_reference<Type>::type result_type; + + template<typename ChainedPtr> Type operator()(const ChainedPtr& x)const; + Type operator()(Class& x)const; + Type operator()(const reference_wrapper<Class>& x)const; +}; +
+The PtrToMemberFunction
template argument specifies the particular
+Type (Class::*PtrToMemberFunction)()
pointer to the the member
+function used in the extraction.
+mem_fun<Class,Type,PtrToMemberFunction>
is a model of:
+
Key Extractor
+ from reference_wrapper<Class>
,Key Extractor
+ from any chained pointer
+ to Class
.mem_fun
memberstemplate<typename ChainedPtr> Type operator()(const ChainedPtr& x)const;
+
++Requires:+ +ChainedPtr
is a chained pointer +type toType
.
+Returns:(y.*PtrToMemberFunction)()
, wherey
is the +object chained-pointed to byx
. +
Type operator()(Class& x)const;
+
+
+Returns: (x.*PtrToMemberFunction)()
.
+
+
+Type operator()(const reference_wrapper<Class>& x)const;
+
+
+Returns: (x.get().*PtrToMemberFunction)()
.
+
+
+const_mem_fun_explicit
+MSVC++ 6.0 do not properly support pointers to constant member functions as non-type
+template parameters, thus const_mem_fun
cannot be
+used in this compiler. A simple workaround consists in specifying the type of
+these pointers as an additional template parameter.
+
+ ++template< + class Class,typename Type, + typename PtrToMemberFunctionType,PtrToMemberFunctionType PtrToMemberFunction +> +struct const_mem_fun_explicit +{ + typedef typename remove_reference<Type>::type result_type; + + template<typename ChainedPtr> Type operator()(const ChainedPtr& x)const; + Type operator()(const Class& x)const; + Type operator()(const reference_wrapper<const Class>& x)const; + Type operator()(const reference_wrapper<Class>& x)const; +}; +
+const_mem_fun_explicit
provides the very same functionality as
+its const_mem_fun
analogous instantiation. For example, given the type
+
+ ++struct A +{ + int f()const; +}; +
+the extractor const_mem_fun<A,int,&A::f>
can be replaced by
+const_mem_fun_explicit<A,int,int (A::*)()const,&A::f>
.
+
mem_fun_explicit
+For analogy with const_mem_fun_explicit
,
+a variation of mem_fun
is provided accepting
+an additional parameter with the type of the pointer to non-constant member function
+used for extraction.
+
+ ++template< + class Class,typename Type, + typename PtrToMemberFunctionType,PtrToMemberFunctionType PtrToMemberFunction +> +struct mem_fun_explicit +{ + typedef typename remove_reference<Type>::type result_type; + + template<typename ChainedPtr> Type operator()(const ChainedPtr& x)const; + Type operator()(Class& x)const; + Type operator()(const reference_wrapper<Class>& x)const; +}; +
BOOST_MULTI_INDEX_CONST_MEM_FUN
+ ++BOOST_MULTI_INDEX_CONST_MEM_FUN(Class,Type,MemberFunName) +
+Use this macro when writing cross-platform code selectively using
+const_mem_fun_explicit
in place of const_mem_fun
for
+compilers not supporting the latter. In the usual cases, the macro expands to
+
+ ++::boost::multi_index::const_mem_fun<Class,Type,&Class::MemberFunName> +
+but it resolves to +
+ ++ ++::boost::multi_index::const_mem_fun_explicit< + Class,Type,Type (Class::*)()const,&Class::MemberFunName +> +
+for MSVC++ 6.0 or lower. +
+ + +BOOST_MULTI_INDEX_MEM_FUN
+ ++BOOST_MULTI_INDEX_MEM_FUN(Class,Type,MemberFunName) +
+By default, the macro expands to +
+ ++ ++::boost::multi_index::mem_fun<Class,Type,&Class::MemberFunName> +
+but it resolves to +
+ ++ ++::boost::multi_index::mem_fun_explicit< + Class,Type,Type (Class::*)(),&Class::MemberFunName +> +
+for MSVC++ 6.0 or lower. +
+ +"boost/multi_index/composite_key.hpp"
synopsis+ ++namespace boost{ + +namespace multi_index{ + +template<typename Value,typename KeyFromValue0,...,typename KeyFromValuen> +struct composite_key; + +template<typename CompositeKey> +struct composite_key_result; + +// comparison for composite_key_result: + +// OP is any of =,<,!=,>,>=,<= + +template<typename CompositeKey1,typename CompositeKey2> +bool operator OP( + const composite_key_result<CompositeKey1>& x, + const composite_key_result<CompositeKey2>& y); + +template<typename CompositeKey,typename Value0,...,typename Valuen> +bool operator OP( + const composite_key_result<CompositeKey>& x, + const tuple<Value0,...,Valuen>& y); + +template<typename Value0,...,typename Valuen,typename CompositeKey> +bool operator OP( + const tuple<Value0,...,Valuen>& x, + const composite_key_result<CompositeKey>& y); + +template<typename Compare0,...,typename Comparen> +struct composite_key_compare; + +template<typename CompositeKeyResult> +struct composite_key_result_less; + +template<typename CompositeKeyResult> +struct composite_key_result_greater; + +} // namespace boost::multi_index + +} // namespace boost + +namespace std{ + +template<typename CompositeKey> +struct less<boost::multi_index::composite_key_result<CompositeKey> >; + +template<typename CompositeKey> +struct greater<boost::multi_index::composite_key_result<CompositeKey> >; + +} // namespace std +
composite_key
+composite_key
is a Key Extractor
+returning the combined value of several key extractors whose type is specified
+at compile time. The returned object is of type
+
+composite_key_result
<composite_key>
.
+
+ ++template<typename Value,typename KeyFromValue0,...,typename KeyFromValuen> +struct composite_key +{ + typedef tuple<KeyFromValue0,...,KeyFromValuen> key_extractor_tuple; + typedef Value value_type; + typedef composite_key_result<composite_key> result_type; + + composite_key( + const KeyFromValue0& k0=KeyFromValue0(), + ... + const KeyFromValuen& kn=KeyFromValuen()); + + composite_key(const key_extractor_tuple& x); + + const key_extractor_tuple& key_extractors()const; + key_extractor_tuple& key_extractors() + + template<typename ChainedPtr> + result_type operator()(const ChainedPtr& x)const; + + result_type operator()(const value_type& x)const; + result_type operator()(const reference_wrapper<const value_type>& x)const; + result_type operator()(const reference_wrapper<value_type>& x)const; +}; +
+KeyFromvalue0
, ... , KeyFromvaluen
are the types of
+the key extractors combined into the composite key. Each of these types
+must be a Key Extractor
from
+Value
. At least a key extractor must be provided. The maximum
+number of key extractors of a composite_key
instantiation is
+implementation defined. composite_key
internally stores an
+object of every constituent key extractor type.
+composite_key<Value,KeyFromValue0,...,KeyFromValuen>
is a model
+of:
+
Key Extractor
+ from Value
,Key Extractor
+ from reference_wrapper<const Value>
,Key Extractor
+ from reference_wrapper<Value>
,Key Extractor
+ from any chained pointer
+ to const Value
,Key Extractor
+ from any chained pointer
+ to Value
.composite_key
memberscomposite_key(
+ const KeyFromValue0& k0=KeyFromValue0(),
+ ...
+ const KeyFromValuen& kn=KeyFromValuen());
+
+
+
+Effects: Constructs a composite_key
that stores
+copies of the key extractor objects supplied.
+
+
+composite_key(const key_extractor_tuple& x);
+
++Effects: Constructs a+ +composite_key
that stores +copies of the key extractor objects supplied inx
. +
const key_extractor_tuple& key_extractors()const;
+
+
+Returns: a constant reference to a tuple holding the
+key extractors internally stored by the composite_key
.
+
+
+key_extractor_tuple& key_extractors();
+
+
+Returns: a reference to a tuple holding the
+key extractors internally stored by the composite_key
.
+
+
+template<typename ChainedPtr>
+result_type operator()(const ChainedPtr& x)const;
+
++Requires:+ +ChainedPtr
is a chained pointer +type toresult_type
.
+Returns: aresult_type
object dependent on +*this
andy
, wherey
is the +object chained-pointed to byx
. +
result_type operator()(const value_type& x)const;
+
++Returns: a+ +result_type
object dependent on +*this
andx
. +
result_type operator()(const reference_wrapper<const value_type>& x)const;
+
++Returns: a+ +result_type
object dependent on +*this
andx.get()
. +
result_type operator()(const reference_wrapper<value_type>& x)const;
+
++Returns: a+ +result_type
object dependent on +*this
andx.get()
. +
composite_key_result
+This is an opaque type returned by composite_key
+instantiations as their extracted key.
+
+ ++template<typename CompositeKey> +struct composite_key_result +{ + no public interface available +}; + +// comparison: + +// OP is any of =,<,!=,>,>=,<= + +template<typename CompositeKey1,typename CompositeKey2> +bool operator OP( + const composite_key_result<CompositeKey1>& x, + const composite_key_result<CompositeKey2>& y); + +template<typename CompositeKey,typename Value0,...,typename Valuen> +bool operator OP( + const composite_key_result<CompositeKey>& x, + const tuple<Value0,...,Valuen>& y); + +template<typename Value0,...,typename Valuen,typename CompositeKey> +bool operator OP( + const tuple<Value0,...,Valuen>& x, + const composite_key_result<CompositeKey>& y); +
CompositeKey
is the composite_key
instantiation to
+which the composite_key_result
type is associated. Objects of type
+composite_key_result
returned by a composite key must be always treated
+as temporary, i.e. they should not be stored or copied.
+composite_key_result
is not guaranteed to be a model of
+
+Default Constructible
or
+Assignable
.
+Every object of type composite_key_result<CompositeKey>
is
+internally asociated to the CompositeKey
from which it is returned
+and the object of type CompositeKey::result_type
to which the
+composite key was applied.
+
+
+
+Given an x
of type composite_key_result<CompositeKey>
,
+we use the following notation:
+
ck(x)
is the CompositeKey
object associated to
+ x
,v(x)
is the object of type CompositeKey::value_type
+ associated to x
,ki(x) = ck(x).key_extractors().get<i>()
,
+ that is, is the i
-th key extractor of ck(x)
,xi = ki(x)(v(x))
, that is, the
+ key extracted from v(x)
by the i
-th key extractor,length(x)
is the number of key extractors of ck(x)
.y
is a tuple of values, we define:
+yi=y.get<i>()
,length(y)
is the number of elements of y
.template<typename CompositeKey1,typename CompositeKey2>
+bool operator==(
+ const composite_key_result<CompositeKey1>& x,
+ const composite_key_result<CompositeKey2>& y);
+template<typename CompositeKey,typename Value0,...,typename Valuen>
+bool operator==(
+ const composite_key_result<CompositeKey>& x,
+ const tuple<Value0,...,Valuen>& y);
+template<typename Value0,...,typename Valuen,typename CompositeKey>
+bool operator==(
+ const tuple<Value0,...,Valuen>& x,
+ const composite_key_result<CompositeKey>& y);
+
+
++Requires:+ +length(x)==length(y)
. The expression +xi==yi
is valid for alli
+in[0,length(x))
. +Returns:true
if and only if +++Complexity: No more key extraction operations and comparisons +are performed than those necessary for the evaluation of the expression above, +starting atxi==yi
for alli
+in[0,length(x))
. +i==0
. The evaluation is short-circuited as soon as +the result is determined to befalse
. +
template<typename CompositeKey1,typename CompositeKey2>
+bool operator<(
+ const composite_key_result<CompositeKey1>& x,
+ const composite_key_result<CompositeKey2>& y);
+template<typename CompositeKey,typename Value0,...,typename Valuen>
+bool operator<(
+ const composite_key_result<CompositeKey>& x,
+ const tuple<Value0,...,Valuen>& y);
+template<typename Value0,...,typename Valuen,typename CompositeKey>
+bool operator<(
+ const tuple<Value0,...,Valuen>& x,
+ const composite_key_result<CompositeKey>& y);
+
+
++Requires: The expressions ++ +xi<yi
and +yi<xi
are valid for alli
+in[0,min(length(x),length(y)))
. +Returns:true
if and only if there exists some +j
in the range[0,min(length(x),length(y)))
+such that +++Complexity: No more key extraction operations and comparisons +are performed than those necessary for the evaluation of the expression above, +starting at!(xi<yi) && !(yi<xi)
+for alli
in[0,j)
,
+xj<yj
. +i==0
. The evaluation is short-circuited as soon as +the result is determined to befalse
. +
template<typename CompositeKey1,typename CompositeKey2>
+bool operator OP(
+ const composite_key_result<CompositeKey1>& x,
+ const composite_key_result<CompositeKey2>& y);
+template<typename CompositeKey,typename Value0,...,typename Valuen>
+bool operator OP(
+ const composite_key_result<CompositeKey>& x,
+ const tuple<Value0,...,Valuen>& y);
+template<typename Value0,...,typename Valuen,typename CompositeKey>
+bool operator OP(
+ const tuple<Value0,...,Valuen>& x,
+ const composite_key_result<CompositeKey>& y);
+
+
+
+(OP
is any of !=
, >
,
+>=
, <=
.)
+
+Requires: The expressions given below are valid (for the particular ++ +OP
considered.) +Returns:true
if and only if +++!(x==y)
(OP
is!=
),
+y< x
(OP
is>
),
+!(x< y)
(OP
is>=
),
+!(y< x)
(OP
is<=
). +
composite_key_compare
+composite_key_compare
compares composite_key_result
+instantiations between them and with tuples of values using an internally stored
+collection of elementary comparison predicates.
+
+ ++template<typename Compare0,...,typename Comparen> +struct composite_key_compare +{ + typedef tuple<Compare0,...,Comparen> key_comp_tuple; + + composite_key_compare( + const Compare0& co=Compare0(), + ... + const Comparen& cn=Comparen()); + + composite_key_compare(const key_comp_tuple& x); + + const key_comp_tuple& key_comps()const{return *this;} + key_comp_tuple& key_comps(){return *this;} + + template<typename CompositeKey1,typename CompositeKey2> + bool operator()( + const composite_key_result<CompositeKey1> & x, + const composite_key_result<CompositeKey2> & y)const; + + template<typename CompositeKey,typename Value0,...,typename Valuen> + bool operator()( + const composite_key_result<CompositeKey>& x, + const tuple<Value0,...,Valuen>& y)const; + + template<typename Value0,...,typename Valuen,typename CompositeKey> + bool operator()( + const tuple<Value0,...,Valuen>& x, + const composite_key_result<CompositeKey>& y)const; +}; +
+Compare0
, ... , Compare0
are the types of the comparison
+predicates stored by composite_key_compare
. Each of these types
+must be a
+Binary Predicate
. At least a
+comparison predicate must be provided. The maximum number of comparison predicates of
+a composite_key_compare
instantiation is implementation defined.
+composite_key_compare
is
+Assignable
.
+It is also
+
+Default Constructible
+if each Comparei
is
+
+Default Constructible
.
+
+Note that formally it is not required that the Comparei
types
+behave as comparison predicates in any definite way. However, the
+semantics of composite_key_compare
are well defined if this
+is the case, as explained in the ordering
+semantics section.
+
+In what follows we use the same notation
+introduced for composite_key_result
.
+
+
composite_key_compare
memberscomposite_key_compare(
+ const Compare0& c0=Compare0(),
+ ...
+ const Comparen& kn=Comparen());
+
+
+
+Effects: Constructs a composite_key_compare
that stores
+copies of the comparison predicates supplied.
+
+
+composite_key_compare(const key_comp_tuple& x);
+
++Effects: Constructs a+ +composite_key_compare
that stores +copies of the comparison predicate objects supplied inx
. +
const key_comp_tuple& key_comps()const;
+
+
+Returns: a constant reference to a tuple holding the
+comparison predicate objects internally stored by the
+composite_key_compare
.
+
+
+key_comp_tuple& key_comps();
+
+
+Returns: a reference to a tuple holding the
+comparison predicate objects internally stored by the
+composite_key_compare
.
+
+
+
+template<typename CompositeKey1,typename CompositeKey2>
+bool operator()(
+ const composite_key_result<CompositeKey1> & x,
+ const composite_key_result<CompositeKey2> & y)const;
+template<typename CompositeKey,typename Value0,...,typename Valuen>
+bool operator()(
+ const composite_key_result<CompositeKey>& x,
+ const tuple<Value0,...,Valuen>& y)const;
+template<typename Value0,...,typename Valuen,typename CompositeKey>
+bool operator()(
+ const tuple<Value0,...,Valuen>& x,
+ const composite_key_result<CompositeKey>& y)const;
+
+
++Requires: The expressions ++ +key_comps().get<i>()(xi,yi)
and +key_comps().get<i>()(yi,xi)
+are valid for alli
+in[0,min(length(x),length(y)))
. +Returns:true
if and only if there exists some +j
in the range[0,min(length(x),length(y)))
+such that +++Complexity: No more key extraction operations and comparisons +are performed than those necessary for the evaluation of the expression above, +starting at!key_comps().get<i>()(xi,yi) && !key_comps().get<i>()(yi,xi)
+for alli
in[0,j)
,
+key_comps().get<j>()(xj,yj)
. +i==0
. The evaluation is short-circuited as soon as +the result is determined to befalse
. +
composite_key_result_less
+composite_key_result
acts as a particularization of
+composite_key_compare
where all the comparison predicates supplied
+are instantiations of std::less
.
+
+ ++template<typename CompositeKeyResult> +struct composite_key_result_less +{ + typedef CompositeKeyResult first_argument_type; + typedef first_argument_type second_argument_type; + typedef bool result_type; + + template<typename CompositeKey1,typename CompositeKey2> + bool operator()( + const composite_key_result<CompositeKey1> & x, + const composite_key_result<CompositeKey2> & y)const; + + template<typename CompositeKey,typename Value0,...,typename Valuen> + bool operator()( + const composite_key_result<CompositeKey>& x, + const tuple<Value0,...,Valuen>& y)const; + + template<typename Value0,...,typename Valuen,typename CompositeKey> + bool operator()( + const tuple<Value0,...,Valuen>& x, + const composite_key_result<CompositeKey>& y)const; +}; +
+CompositeKeyResult
must be an instantiation of
+composite_key_result
for some type
+composite_key<KeyFromValue0,...,KeyFromValuen>
.
+composite_key_result_less<CompositeKeyResult>::operator()
is
+then equivalent to
+composite_key_compare<Compare0,...,Comparen>::operator()
, taking
+
++ + +Comparei = std::less<KeyFromValuei::result_type>
for all +i = 0,...,n
. +
+In addition to the requirements on Comparei
imposed by
+composite_key_compare
, each of these types must be
+
+Default Constructible
. composite_key_result_less
+is
+Default Constructible
and
+Assignable
.
+
composite_key_result_greater
+composite_key_result
acts as a particularization of
+composite_key_compare
where all the comparison predicates supplied
+are instantiations of std::greater
.
+
+ ++template<typename CompositeKeyResult> +struct composite_key_result_greater +{ + typedef CompositeKeyResult first_argument_type; + typedef first_argument_type second_argument_type; + typedef bool result_type; + + template<typename CompositeKey1,typename CompositeKey2> + bool operator()( + const composite_key_result<CompositeKey1> & x, + const composite_key_result<CompositeKey2> & y)const; + + template<typename CompositeKey,typename Value0,...,typename Valuen> + bool operator()( + const composite_key_result<CompositeKey>& x, + const tuple<Value0,...,Valuen>& y)const; + + template<typename Value0,...,typename Valuen,typename CompositeKey> + bool operator()( + const tuple<Value0,...,Valuen>& x, + const composite_key_result<CompositeKey>& y)const; +}; +
+CompositeKeyResult
must be an instantiation of
+composite_key_result
for some type
+composite_key<KeyFromValue0,...,KeyFromValuen>
.
+composite_key_result_greater<CompositeKeyResult>::operator()
is
+then equivalent to
+composite_key_compare<Compare0,...,Comparen>::operator()
, taking
+
++ + +Comparei = std::greater<KeyFromValuei::result_type>
for all +i = 0,...,n
. +
+In addition to the requirements on Comparei
imposed by
+composite_key_compare
, each of these types must be
+
+Default Constructible
. composite_key_result_greater
+is
+Default Constructible
and
+Assignable
.
+
std::less
for
+composite_key
results
+std::less<CompositeKeyResult>
, for CompositeKeyResult
+being an instantiation of composite_key_result
, has the same interface
+and functionality that composite_key_result_less<CompositeKeyResult>
.
+
+ ++namespace std{ + +template<typename CompositeKey> +struct less<boost::multi_index::composite_key_result<CompositeKey> > +{ + typedef CompositeKeyResult first_argument_type; + typedef first_argument_type second_argument_type; + typedef bool result_type; + + template<typename CompositeKey1,typename CompositeKey2> + bool operator()( + const composite_key_result<CompositeKey1> & x, + const composite_key_result<CompositeKey2> & y)const; + + template<typename CompositeKey,typename Value0,...,typename Valuen> + bool operator()( + const composite_key_result<CompositeKey>& x, + const tuple<Value0,...,Valuen>& y)const; + + template<typename Value0,...,typename Valuen,typename CompositeKey> + bool operator()( + const tuple<Value0,...,Valuen>& x, + const composite_key_result<CompositeKey>& y)const; +}; + +} // namespace std +
std::greater
for
+composite_key
results
+std::greater<CompositeKeyResult>
, for CompositeKeyResult
+being an instantiation of composite_key_result
, has the same interface
+and functionality that composite_key_result_greater<CompositeKeyResult>
.
+
+ ++namespace std{ + +template<typename CompositeKey> +struct greater<boost::multi_index::composite_key_result<CompositeKey> > +{ + typedef CompositeKeyResult first_argument_type; + typedef first_argument_type second_argument_type; + typedef bool result_type; + + template<typename CompositeKey1,typename CompositeKey2> + bool operator()( + const composite_key_result<CompositeKey1> & x, + const composite_key_result<CompositeKey2> & y)const; + + template<typename CompositeKey,typename Value0,...,typename Valuen> + bool operator()( + const composite_key_result<CompositeKey>& x, + const tuple<Value0,...,Valuen>& y)const; + + template<typename Value0,...,typename Valuen,typename CompositeKey> + bool operator()( + const tuple<Value0,...,Valuen>& x, + const composite_key_result<CompositeKey>& y)const; +}; + +} // namespace std +
+Consider an instantiation of composite_key_compare
with
+types Compare0
, ... , Comparen
such that each
+Comparei
is a
+Strict
+Weak Ordering
on a certain type Ti
. Then the following
+properties hold.
+
+Let CompositeKey
be a type of the form
+composite_key<Value,KeyFromValue0,...,KeyFromValuej>
,
+with j <= n
, such that
+
++Then,KeyFromValuei::result_type = Ti
, for alli = 0,...,j
. +
composite_key_compare
is a
+Strict
+Weak Ordering
on elements of type
+composite_key_result<CompositeKey>
, and the order induced
+is lexicographical. Also, the following types are
+Compatible Keys
of
+composite_key_compare
with respect to
+composite_key_result<CompositeKey>
:
+++provided that eachtuple<Q0,...,Qk>
,k <= n
+composite_key_result<composite_key<K0,...,Kk> >
, with +Ki::result_type = Qi
for alli = 0,...,k
. +
Qi
is either Ti
or a
+Compatible Key
+of Comparei
. In this case, the comparison is done
+lexicographically only on the first 1+min(j,k)
elements.
+
+
+
+The rationale of this design is simple:
+composite_key_result
s are regarded as "virtual" tuples
+with each element being the result of the corresponding elementary key
+extractor. Accordingly, these objects and actual tuples are compared
+lexicographically taking the minimum length of the operands considered.
+
+Analogous properties hold for
+composite_key_result::operator<
. As for
+operator==
, the semantics is compatible with that of
+less-than comparison, with the additional constraint that only objects
+of the same length can be tested for equality. In this regard,
+the equivalence classes induced by x==y
are subsets
+of those associated to !(x<y)&&!(y<x)
.
+
Revised May 7th 2004
+ +Copyright © 2003-2004 Joaquín M López Muñoz. +Use, modification, and distribution are subject to the Boost Software +License, Version 1.0. (See accompanying file +LICENSE_1_0.txt or copy at +www.boost.org/LICENSE_1_0.txt) +
+ + + diff --git a/doc/reference/multi_index_container.html b/doc/reference/multi_index_container.html new file mode 100644 index 0000000..85ca13b --- /dev/null +++ b/doc/reference/multi_index_container.html @@ -0,0 +1,831 @@ + + + + + +multi_index_container
reference"boost/multi_index_container_fwd.hpp"
synopsis"boost/multi_index_container.hpp"
synopsis
+
+ "boost/multi_index_container_fwd.hpp"
+synopsis
++ ++namespace boost{ + +namespace multi_index{ + +template< + typename Value, + typename IndexSpecifierList=indexed_by<ordered_unique<identity<Value> > >, + typename Allocator=std::allocator<Value> > +class multi_index_container; + +} // namespace boost::multi_index + +using multi_index::multi_index_container; + +} // namespace boost +
+multi_index_container_fwd.hpp
forward declares the class template
+multi_index_container
and specifies its default parameters.
+
"boost/multi_index_container.hpp"
+synopsis
++ ++namespace boost{ + +namespace multi_index{ + +template<typename Value,typename IndexSpecifierList,typename Allocator> +class multi_index_container; + +// multi_index_container associated global class templates: + +template<typename MultiIndexContainer,int N> struct nth_index; +template<typename MultiIndexContainer,typename Tag> struct index; +template<typename MultiIndexContainer,int N> struct nth_index_iterator; +template<typename MultiIndexContainer,int N> struct nth_index_const_iterator; +template<typename MultiIndexContainer,typename Tag> struct index_iterator; +template<typename MultiIndexContainer,typename Tag> struct index_const_iterator; + +// multi_index_container global functions for index retrieval: + +template< + int N,typename Value,typename IndexSpecifierList,typename Allocator +> +typename nth_index< + multi_index_container<Value,IndexSpecifierList,Allocator>,N +>::type& +get(multi_index_container<Value,IndexSpecifierList,Allocator>& m); + +template< + int N,typename Value,typename IndexSpecifierList,typename Allocator +> +const typename nth_index< + multi_index_container<Value,IndexSpecifierList,Allocator>,N +>::type& +get(const multi_index_container<Value,IndexSpecifierList,Allocator>& m); + +template< + typename Tag,typename Value,typename IndexSpecifierList,typename Allocator +> +typename index< + multi_index_container<Value,IndexSpecifierList,Allocator>,Tag +>::type& +get(multi_index_container<Value,IndexSpecifierList,Allocator>& m); + +template< + typename Tag,typename Value,typename IndexSpecifierList,typename Allocator +> +const typename index< + multi_index_container<Value,IndexSpecifierList,Allocator>,Tag +>::type& +get(const multi_index_container<Value,IndexSpecifierList,Allocator>& m); + +// multi_index_container global functions for projection of iterators: + +template< + int N,typename IteratorType, + typename Value,typename IndexSpecifierList,typename Allocator +> +typename nth_index_iterator< + multi_index_container<Value,IndexSpecifierList,Allocator>,N +>::type +project( + multi_index_container<Value,IndexSpecifierList,Allocator>& m, + IteratorType it); + +template< + int N,typename IteratorType, + typename Value,typename IndexSpecifierList,typename Allocator +> +typename nth_index_const_iterator< + multi_index_container<Value,IndexSpecifierList,Allocator>,N +>::type +project( + const multi_index_container<Value,IndexSpecifierList,Allocator>& m, + IteratorType it); + +template< + typename Tag,typename IteratorType, + typename Value,typename IndexSpecifierList,typename Allocator +> +typename index_iterator< + multi_index_container<Value,IndexSpecifierList,Allocator>,Tag +>::type +project( + multi_index_container<Value,IndexSpecifierList,Allocator>& m, + IteratorType it); + +template< + typename Tag,typename IteratorType, + typename Value,typename IndexSpecifierList,typename Allocator +> +typename index_const_iterator< + multi_index_container<Value,IndexSpecifierList,Allocator>,Tag +>::type +project( + const multi_index_container<Value,IndexSpecifierList,Allocator>& m, + IteratorType it); + +// comparison: + +// OP is any of ==,<,!=,>,>=,<= + +template< + typename Value1,typename IndexSpecifierList1,typename Allocator1, + typename Value2,typename IndexSpecifierList2,typename Allocator2 +> +bool operator OP( + const multi_index_container<Value1,IndexSpecifierList1,Allocator1>& x, + const multi_index_container<Value2,IndexSpecifierList2,Allocator2>& y); + +// specialized algorithms: + +template<typename Value,typename IndexSpecifierList,typename Allocator> +void swap( + multi_index_container<Value,IndexSpecifierList,Allocator>& x, + multi_index_container<Value,IndexSpecifierList,Allocator>& y); + +} // namespace boost::multi_index + +using multi_index::multi_index_container; +using multi_index::get; +using multi_index::project; + +} // namespace boost +
multi_index_container
+
+This is the main component of Boost.MultiIndex. A multi_index_container
+is a container class template holding a compile-time user-defined list of
+indices. These indices provide different interfaces
+for the management of the elements of the multi_index_container
. By itself,
+multi_index_container
only provides basic functionality for construction
+and for access to the indices held.
+
+A multi_index_container
type is instantiated with the type of the
+elements contained and a non-empty
+
+MPL Forward Sequence
specifying which indices conform the
+class.
+
+For convenience of use, all public methods and types of the first index
+specified are inherited by multi_index_container
. This also includes global
+operators and functions associated with the index (vg. comparison and
+swap
.)
+
+ ++template< + typename Value, + typename IndexSpecifierList=indexed_by<ordered_unique<identity<Value> > >, + typename Allocator=std::allocator<Value> > +class multi_index_container +{ +public: + + // types: + + typedef implementation defined ctor_args_list; + typedef implementation defined index_specifier_type_list; + typedef implementation defined index_type_list; + typedef implementation defined iterator_type_list; + typedef implementation defined const_iterator_type_list; + typedef Allocator allocator_type; + + // nested class templates: + + template<int N> + struct nth_index {typedef implementation defined type;}; + template<typename Tag> + struct index {typedef implementation defined type;}; + template<int N> + struct nth_index_iterator {typedef implementation defined type;}; + template<int N> + struct nth_index_const_iterator {typedef implementation defined type;}; + template<typename Tag> + struct index_iterator {typedef implementation defined type;}; + template<typename Tag> + struct index_const_iterator {typedef implementation defined type;}; + + // construct/copy/destroy: + + explicit multi_index_container( + const ctor_args_list& args_list=ctor_args_list(), + const allocator_type& al=allocator_type()); + template<typename InputIterator> + multi_index_container( + InputIterator first,InputIterator last, + const ctor_args_list& args_list=ctor_args_list(), + const allocator_type& al=allocator_type()); + multi_index_container( + const multi_index_container<Value,IndexSpecifierList,Allocator>& x); + + ~multi_index_container(); + + multi_index_container<Value,IndexSpecifierList,Allocator>& operator=( + const multi_index_container<Value,IndexSpecifierList,Allocator>& x); + + allocator_type get_allocator()const; + + // retrieval of indices + + template<int N> typename nth_index<N>::type& get(); + template<int N> const typename nth_index<N>::type& get()const; + template<typename Tag> typename index<Tag>::type& get() + template<typename Tag> const typename index<Tag>::type& get()const; + + // projection of iterators + + template<int N,typename IteratorType> + typename nth_index_iterator<N>::type project(IteratorType it); + template<int N,typename IteratorType> + typename nth_index_const_iterator<N>::type project(IteratorType it)const; + template<typename Tag,typename IteratorType> + typename index_iterator<Tag>::type project(IteratorType it); + template<typename Tag,typename IteratorType> + typename index_const_iterator<Tag>::type project(IteratorType it)const; +}; + +// multi_index_container associated global class templates: + +template<typename MultiIndexContainer,int N> struct nth_index +{ + typedef typename MultiIndexContainer::nth_index<N>::type type; +}; + +template<typename MultiIndexContainer,typename Tag> struct index +{ + typedef typename MultiIndexContainer::index<Tag>::type type; +}; + +template<typename MultiIndexContainer,int N> struct nth_index_iterator +{ + typedef typename MultiIndexContainer::nth_index_iterator<N>::type type; +}; + +template<typename MultiIndexContainer,int N> struct nth_index_const_iterator +{ + typedef typename MultiIndexContainer::nth_index_const_iterator<N>::type type; +}; + +template<typename MultiIndexContainer,typename Tag> struct index_iterator +{ + typedef typename MultiIndexContainer::index_iterator<Tag>::type type; +}; + +template<typename MultiIndexContainer,typename Tag> struct index_const_iterator +{ + typedef typename MultiIndexContainer::index_const_iterator<Tag>::type type; +}; + +// multi_index_container global functions for index retrieval: + +template< + int N,typename Value,typename IndexSpecifierList,typename Allocator +> +typename nth_index< + multi_index_container<Value,IndexSpecifierList,Allocator>,N +>::type& +get(multi_index_container<Value,IndexSpecifierList,Allocator>& m) +{ + return m.get<N>(); +} + +template< + int N,typename Value,typename IndexSpecifierList,typename Allocator +> +const typename nth_index< + multi_index_container<Value,IndexSpecifierList,Allocator>,N +>::type& +get(const multi_index_container<Value,IndexSpecifierList,Allocator>& m) +{ + return m.get<N>(); +} + +template< + typename Tag,typename Value,typename IndexSpecifierList,typename Allocator +> +typename index< + multi_index_container<Value,IndexSpecifierList,Allocator>,Tag +>::type& +get(multi_index_container<Value,IndexSpecifierList,Allocator>& m) +{ + return m.get<Tag>(); +} + +template< + typename Tag,typename Value,typename IndexSpecifierList,typename Allocator +> +const typename index< + multi_index_container<Value,IndexSpecifierList,Allocator>,Tag +>::type& +get(const multi_index_container<Value,IndexSpecifierList,Allocator>& m) +{ + return m.get<Tag>(); +} + +// multi_index_container global functions for projection of iterators: + +template< + int N,typename IteratorType, + typename Value,typename IndexSpecifierList,typename Allocator +> +typename nth_index_iterator< + multi_index_container<Value,IndexSpecifierList,Allocator>,N +>::type +project( + multi_index_container<Value,IndexSpecifierList,Allocator>& m, + IteratorType it) +{ + return m.project<N>(it); +} + +template< + int N,typename IteratorType, + typename Value,typename IndexSpecifierList,typename Allocator +> +typename nth_index_const_iterator< + multi_index_container<Value,IndexSpecifierList,Allocator>,N +>::type +project( + const multi_index_container<Value,IndexSpecifierList,Allocator>& m, + IteratorType it) +{ + return m.project<N>(it); +} + +template< + typename Tag,typename IteratorType, + typename Value,typename IndexSpecifierList,typename Allocator +> +typename index_iterator< + multi_index_container<Value,IndexSpecifierList,Allocator>,Tag +>::type +project( + multi_index_container<Value,IndexSpecifierList,Allocator>& m, + IteratorType it) +{ + return m.project<Tag>(it); +} + +template< + typename Tag,typename IteratorType, + typename Value,typename IndexSpecifierList,typename Allocator +> +typename index_const_iterator< + multi_index_container<Value,IndexSpecifierList,Allocator>,Tag +>::type +project( + const multi_index_container<Value,IndexSpecifierList,Allocator>& m, + IteratorType it) +{ + return m.project<Tag>(it); +} + +// comparison: + +// OP is any of ==,<,!=,>,>=,<= + +template< + typename Value1,typename IndexSpecifierList1,typename Allocator1, + typename Value2,typename IndexSpecifierList2,typename Allocator2 +> +bool operator OP( + const multi_index_container<Value1,IndexSpecifierList1,Allocator1>& x, + const multi_index_container<Value2,IndexSpecifierList2,Allocator2>& y) + { + return get<0>(x) OP get<0>(y); + } + +// specialized algorithms: + +template<typename Value,typename IndexSpecifierList,typename Allocator> +void swap( + multi_index_container<Value,IndexSpecifierList,Allocator>& x, + multi_index_container<Value,IndexSpecifierList,Allocator>& y) + { + x.swap(y); + } + +} // namespace boost::multi_index + +} // namespace boost +
+In the descriptions of operations of multi_index_container
, we adopt the
+scheme outlined in the
+complexity signature section.
+
+multi_index_container
is instantiated with the following types:
+
Value
is the
+ Assignable
+ type of the elements contained.IndexSpecifierList
specifies the indices that the
+ multi_index_container
is composed of. It must be a non-empty
+
+ MPL Forward Sequence
of index specifiers. For
+ syntactic convenience, the
+ indexed_by
+ MPL sequence can be used.
+ Allocator
must comply with the C++ requirements for
+ allocators [lib.allocator.requirements].
+multi_index_container
instantiation cannot have
+duplicate tags, either within a single
+index or in two different indices.
+
+
+ctor_args_list
+
++Although the exact definition of+ +ctor_args_list
is +implementation defined, from the user point of view this type can be +treated as equivalent to +::boost::tuple<C0,...,CI-1>
, +whereCi
is thector_args
type of the +i
-th index held by themulti_index_container
, in the +same order as they were specified. Strictly speaking, there is an +implicit conversion from +const ::boost::tuple<C0,...,CI-1>&
+toconst ctor_args_list&
. This type is used for +providing the construction arguments of the indices of the +multi_index_container
.ctor_args_list
is +Default +Constructible
, provided that allctor_args
types +involved are default constructible. +
index_specifier_type_list
+
++ ++ +MPL Forward Sequence
containing the types of the index specifiers +used in the instantiation of themulti_index_container
, in the same order as +they were provided. +
index_type_list
+
++ ++ +MPL Forward Sequence
containing the types of the indices held by +themulti_index_container
, in the same order as they were specified. +
iterator_type_list
+
++ ++ +MPL Forward Sequence
containing the types of the iterators of +the indices held by themulti_index_container
, in the same order as they were +specified. +
const_iterator_type_list
+
++ ++ +MPL Forward Sequence
containing the types of the constant +iterators of the indices held by themulti_index_container
, in the same order +as they were specified. +
template<int N> struct nth_index
+
+++ +nth_index<N>::type
yields the type of the +N
-th (0-based) index held by themulti_index_container
, in +the same order as they were specified.
+Requires:0 <= N < I
. +
template<typename Tag> struct index
+
+++ +index<Tag>::type
yields the type of the index which +hasTag
as an associated tag type. +Requires: Some index of themulti_index_container
hasTag
+as an associated tag type. +
template<int N> struct nth_index_iterator
+
+++ +nth_index_iterator<N>::type
is equivalent to +nth_index<N>::type::iterator
.
+
template<int N> struct nth_index_const_iterator
+
+++ +nth_index_const_iterator<N>::type
is equivalent to +nth_index<N>::type::const_iterator
.
+
template<typename Tag> struct index_iterator
+
+++ +index_iterator<Tag>::type
is equivalent to +index<Tag>::type::iterator
.
+
template<typename Tag> struct index_const_iterator
+
+++ +index_const_iterator<Tag>::type
is equivalent to +index<Tag>::type::const_iterator
.
+
explicit multi_index_container(
+ const ctor_args_list& comp=ctor_args_list(),
+ const allocator_type& al=allocator_type());
+
++Effects: Constructs an empty+ +multi_index_container
using the +specified argument list and allocator.
+Complexity: Constant. +
template<typename InputIterator>
+multi_index_container(
+ InputIterator first,InputIterator last,
+ const ctor_args_list& comp=ctor_args_list(),
+ const allocator_type& al=allocator_type());
+
++Requires:+ +InputIterator
is a model of + +Input Iterator
over elements of type +Value
or a type convertible toValue
. +last
is reachable fromfirst
. +Effects: Constructs and emptymulti_index_container
using the +specified argument list and allocator and fills it with +the elements in the range [first
,last
). +Insertion of each element may or may not succeed depending +on the acceptance by all the indices of themulti_index_container
.
+Complexity:O(m*H(m))
, wherem
is +the number of elements in [first
,last
).
+
multi_index_container(
+ const multi_index_container<Value,IndexSpecifierList,Allocator>& x);
+
++Effects: Constructs a copy of+ +x
, copying its +elements as well as its internal objects (key extractors, comparison objects, +allocator.)
+Postconditions:*this==x
. The order on every index +of themulti_index_container
is preserved as well.
+Complexity:O(x.size()*log(x.size()) + C(x.size()))
. +
~multi_index_container()
++Effects: Destroys the+ +multi_index_container
and all the elements +contained. The order in which the elements are destroyed is not specified.
+Complexity:O(n*D(n))
. +
multi_index_container<Value,IndexSpecifierList,Allocator>& operator=(
+ const multi_index_container<Value,IndexSpecifierList,Allocator>& x);
+
++Replaces the elements and internal objects of the+ +multi_index_container
+with copies fromx
.
+Postconditions:*this==x
. The order on every index +of themulti_index_container
is preserved as well.
+Returns:*this
.
+Complexity:O(n*D(n) + x.size()*log(x.size()) + +C(x.size()))
.
+Exception safety: Strong, provided the copy and assignment operations +of the types ofctor_args_list
do not throw. +
allocator_type get_allocator()const;
+
++Returns a copy of the+ +allocator_type
object used to construct +themulti_index_container
.
+Complexity: Constant. +
template<int N> typename nth_index<N>::type& get();
+
++Requires:+ +0 <= N < I
.
+Effects: Returns a reference to the +nth_index<N>::type
index held by*this
.
+Complexity: Constant.
+Exception safety:nothrow
. +
template<int N> const typename nth_index<N>::type& get()const;
+
++Requires:+ +0 <= N < I
.
+Effects: Returns aconst
reference to the +nth_index<N>::type
index held by*this
.
+Complexity: Constant.
+Exception safety:nothrow
. +
template<typename Tag> typename index<Tag>::type& get()
+
++Requires:+ +Tag
is such thatindex<Tag>::type
+is valid.
+Effects: Returns a reference to the +index<Tag>::type
index held by +*this
.
+Complexity: Constant.
+Exception safety:nothrow
. +
template<typename Tag> const typename index<Tag>::type& get()const;
+
++Requires:+ +Tag
is such thatindex<Tag>::type
+is valid.
+Effects: Returns aconst
reference to the +index<Tag>::type
index held by +*this
.
+Complexity: Constant.
+Exception safety:nothrow
. +
+Given a multi_index_container
with indices i1
+and i2
, we say than an i1
-iterator
+it1
and an i2
-iterator it2
+are equivalent if:
+
it1==i1.end()
AND it2==i2.end()
,it1
and it2
point to the
+ same element.template<int N,typename IteratorType>
+typename nth_index_iterator<N>::type project(IteratorType it);
+
++Requires:+ +0 <= N < I
.IteratorType
+belongs toiterator_type_list
.it
is a valid +iterator of some index of*this
(i.e. does not refer to some +othermulti_index_container
.)
+Effects: Returns annth_index_iterator<N>::type
iterator +equivalent toit
.
+Complexity: Constant.
+Exception safety:nothrow
. +
template<int N,typename IteratorType>
+typename nth_index_const_iterator<N>::type project(IteratorType it)const;
+
++Requires:+ +0 <= N < I
.IteratorType
+belongs toconst_iterator_type_list
or +iterator_type_list
.it
is a +valid (constant or non-constant) iterator of some index of*this
+(i.e. does not refer to some othermulti_index_container
.)
+Effects: Returns annth_index_const_iterator<N>::type
+iterator equivalent toit
.
+Complexity: Constant.
+Exception safety:nothrow
. +
template<typename Tag,typename IteratorType>
+typename index_iterator<Tag>::type project(IteratorType it);
+
++Requires:+ +Tag
is such that +index_iterator<Tag>::type
is valid.IteratorType
+belongs toiterator_type_list
.it
is a valid +iterator of some index of*this
(i.e. does not refer to some +othermulti_index_container
.)
+Effects: Returns anindex_iterator<Tag>::type
iterator +equivalent toit
.
+Complexity: Constant.
+Exception safety:nothrow
. +
template<typename Tag,typename IteratorType>
+typename index_const_iterator<Tag>::type project(IteratorType it)const;
+
++Requires:+ +Tag
is such that +index_const_iterator<Tag>::type
is valid.IteratorType
+belongs toconst_iterator_type_list
or +iterator_type_list
.it
is a valid +(constant or non-constant) iterator of some index of*this
+(i.e. does not refer to some othermulti_index_container
.)
+Effects: Returns anindex_const_iterator<Tag>::type
+iterator equivalent toit
.
+Complexity: Constant.
+Exception safety:nothrow
. +
Revised May 7th 2004
+ +Copyright © 2003-2004 Joaquín M López Muñoz. +Use, modification, and distribution are subject to the Boost Software +License, Version 1.0. (See accompanying file +LICENSE_1_0.txt or copy at +www.boost.org/LICENSE_1_0.txt) +
+ + + diff --git a/doc/reference/ord_indices.html b/doc/reference/ord_indices.html new file mode 100644 index 0000000..a64b64a --- /dev/null +++ b/doc/reference/ord_indices.html @@ -0,0 +1,909 @@ + + + + + +"boost/multi_index/ordered_index_fwd.hpp"
synopsis"boost/multi_index/ordered_index.hpp"
synopsis
+
+ "boost/multi_index/ordered_index_fwd.hpp"
synopsis+ ++namespace boost{ + +namespace multi_index{ + +// index specifiers unique and ordered_non_unique + +template<consult ordered_unique reference for arguments> +struct ordered_unique; +template<consult ordered_non_unique reference for arguments> +struct ordered_non_unique; + +// indices + +namespace detail{ + +template<implementation defined> class index name is implementation defined; + +} // namespace boost::multi_index::detail + +} // namespace boost::multi_index + +} // namespace boost +
+index_fwd.hpp
provides forward declarations for index specifiers
+ordered_unique
and ordered_non_unique
and
+their associated ordered index classes.
+
"boost/multi_index/ordered_index.hpp"
synopsis+ ++namespace boost{ + +namespace multi_index{ + +// index specifiers unique and ordered_non_unique + +template<consult ordered_unique reference for arguments> +struct ordered_unique; +template<consult ordered_non_unique reference for arguments> +struct ordered_non_unique; + +// indices + +namespace detail{ + +template<implementation defined> class index class name implementation defined; + +// index comparison: + +// OP is any of ==,<,!=,>,>=,<= + +template<arg set 1,arg set 2> +bool operator OP( + const index class name<arg set 1>& x,const index class name<arg set 2>& y); + +// index specialized algorithms: + +template<implementation defined> +void swap(index class name& x,index class name& y); + +} // namespace boost::multi_index::detail + +} // namespace boost::multi_index + +} // namespace boost +
ordered_unique
and ordered_non_unique
+
+These index specifiers allow
+for insertion of ordered indices without and with
+allowance of duplicate elements, respectively. The syntax of ordered_unique
+and ordered_non_unique
coincide, thus we describe them in a grouped manner.
+ordered_unique
and ordered_non_unique
can be instantiated in
+two different forms, according to whether a tag list for the index is provided or not:
+
+ ++template< + typename KeyFromValue, + typename Compare=std::less<KeyFromValue::result_type +> +struct (ordered_unique | ordered_non_unique); + +template< + typename TagList, + typename KeyFromValue, + typename Compare=std::less<KeyFromValue::result_type> +> +struct (ordered_unique | ordered_non_unique); +
+If provided, TagList
must be an instantiation of the class template
+tag
.
+The template arguments are used by the corresponding index implementation,
+refer to the ordered indices reference section for further
+explanations on their acceptable type values.
+
+An ordered index provides a set-like interface to the underlying heap of
+elements contained in a multi_index_container
. An ordered index is
+particularized according to a given
+Key Extractor
+that retrieves keys from elements of multi_index_container
and a comparison
+predicate.
+
+There are two variants of ordered indices: unique, which do +not allow duplicate elements (with respect to its associated comparison +predicate) and non-unique, which accept those duplicates. +The interface of these two variants is the same, so they are documented +together, with minor differences explicitly stated when they exist. +
+ +
+Except where noted, ordered indices (both unique and non-unique) are models of
+
+Sorted Associative Container
and
+
+Unique Associative Container
, much as std::set
s
+are. Accordingly, validity of iterators and references to elements is
+preserved. We only provide descriptions of those types and operations that are
+either not present in the concepts modeled or do not exactly conform to the
+requirements for these types of containers.
+
+ ++namespace boost{ + +namespace multi_index{ + +namespace{ implementation defined unbounded; } // see range() + +namespace detail{ + +template<implementation defined: dependent on types Value, Allocator, + TagList, KeyFromValue, Compare> +class name is implementation defined +{ +public: + // types: + + typedef typename KeyFromValue::result_type key_type; + typedef Value value_type; + typedef KeyFromValue key_from_value; + typedef Compare key_compare; + typedef implementation defined value_compare; + typedef tuple<key_from_value,key_compare> ctor_args; + typedef Allocator allocator_type; + typedef typename Allocator::reference reference; + typedef typename Allocator::const_reference const_reference; + typedef implementation defined iterator; + typedef implementation defined const_iterator; + typedef implementation defined size_type; + typedef implementation defined difference_type; + typedef typename Allocator::pointer pointer; + typedef typename Allocator::const_pointer const_pointer; + typedef equivalent to + std::reverse_iterator<iterator> reverse_iterator; + typedef equivalent to + std::reverse_iterator<const_iterator> const_reverse_iterator; + + // construct/copy/destroy: + + index class name& operator=(const index class name& x); + + allocator_type get_allocator()const; + + // iterators: + + iterator begin(); + const_iterator begin()const; + iterator end(); + const_iterator end()const; + reverse_iterator rbegin(); + const_reverse_iterator rbegin()const; + reverse_iterator rend(); + const_reverse_iterator rend()const; + + // capacity: + + bool empty()const; + size_type size()const; + size_type max_size()const; + + // modifiers: + + std::pair<iterator,bool> insert(const value_type& x); + iterator insert(iterator position,const value_type& x); + template<typename InputIterator> + void insert(InputIterator first,InputIterator last); + + void erase(iterator position); + size_type erase(const key_type& x); + void erase(iterator first,iterator last); + + bool replace(iterator position,const value_type& x); + template<typename Modifier> bool modify(iterator position,Modifier mod); + template<typename Modifier> bool modify_key(iterator position,Modifier mod); + + void swap(index class name& x); + void clear(); + + // observers: + + key_from_value key_extractor()const; + key_compare key_comp()const; + value_compare value_comp()const; + + // set operations: + + template<typename CompatibleKey> + const_iterator find(const CompatibleKey& x)const; + template<typename CompatibleKey,typename CompatibleCompare> + const_iterator find( + const CompatibleKey& x,const CompatibleCompare& comp)const; + + template<typename CompatibleKey> + size_type count(const CompatibleKey& x)const; + template<typename CompatibleKey,typename CompatibleCompare> + size_type count(const CompatibleKey& x,const CompatibleCompare& comp)const; + + template<typename CompatibleKey> + const_iterator lower_bound(const CompatibleKey& x)const; + template<typename CompatibleKey,typename CompatibleCompare> + const_iterator lower_bound( + const CompatibleKey& x,const CompatibleCompare& comp)const; + + template<typename CompatibleKey> + const_iterator upper_bound(const CompatibleKey& x)const; + template<typename CompatibleKey,typename CompatibleCompare> + const_iterator upper_bound( + const CompatibleKey& x,const CompatibleCompare& comp)const; + + template<typename CompatibleKey> + std::pair<const_iterator,const_iterator> equal_range( + const CompatibleKey& x)const; + template<typename CompatibleKey,typename CompatibleCompare> + std::pair<const_iterator,const_iterator> equal_range( + const CompatibleKey& x,const CompatibleCompare& comp)const; + + // range: + + template<typename LowerBounder,typename UpperBounder> + std::pair<const_iterator,const_iterator> range( + LowerBounder lower,UpperBounder upper)const; +}; + +// index comparison: + +template<arg set 1,arg set 2> +bool operator==( + const index class name<arg set 1>& x, + const index class name<arg set 2>& y) +{ + return x.size()==y.size()&&std::equal(x.begin(),x.end(),y.begin()); +} + +template<arg set 1,arg set 2> +bool operator<( + const index class name<arg set 1>& x, + const index class name<arg set 2>& y) +{ + return std::lexicographical_compare(x.begin(),x.end(),y.begin(),y.end()); +} + +template<arg set 1,arg set 2> +bool operator!=( + const index class name<arg set 1>& x, + const index class name<arg set 2>& y) +{ + return !(x==y); +} + +template<arg set 1,arg set 2> +bool operator>( + const index class name<arg set 1>& x, + const index class name<arg set 2>& y) +{ + return y<x; +} + +template<arg set 1,arg set 2> +bool operator>=( + const index class name<arg set 1>& x, + const index class name<arg set 2>& y) +{ + return !(x<y); +} + +template<arg set 1,arg set 2> +bool operator<=( + const index class name<arg set 1>& x, + const index class name<arg set 2>& y) +{ + return !(x>y); +} + +// index specialized algorithms: + +template<implementation defined> +void swap(index class name& x,index class name& y); + +} // namespace boost::multi_index::detail + +} // namespace boost::multi_index + +} // namespace boost +
+Here and in the descriptions of operations of ordered indices, we adopt the +scheme outlined in the +complexity signature +section. The complexity signature of ordered indices is: +
c(n)=n*log(n)
,i(n)=log(n)
,h(n)=1
(constant) if the hint element
+ precedes the point of insertion, h(n)=log(n)
otherwise,d(n)=1
(constant),r(n)=1
(constant) if the element position does not
+ change, r(n)=log(n)
otherwise,m(n)=1
(constant) if the element position does not
+ change, m(n)=log(n)
otherwise.Ordered indices are instantiated internally to multi_index_container
and
+specified by means of indexed_by
+with index specifiers ordered_unique
+and ordered_non_unique
. Instantiations are dependent on the
+following types:
+
Value
from multi_index_container
,Allocator
from multi_index_container
,TagList
from the index specifier (if provided),KeyFromValue
from the index specifier,Compare
from the index specifier.TagList
must be an instantiation of
+tag
. The type KeyFromValue
,
+which determines the mechanism for extracting a key from Value
,
+must be a model of
+Key Extractor
from Value
. Compare
is a
+
+Strict Weak Ordering
on elements of
+KeyFromValue::result_type
.
+
+
++As explained in the index +concepts section, indices do not have public constructors or destructors. +Assignment, on the other hand, is provided. +
+ +index class name& operator=(const index class name& x);
+
++Effects: ++ ++where+a=b; +a
andb
are themulti_index_container
+objects to which*this
andx
belongs, respectively.
+Returns:*this
.
+
std::pair<iterator,bool> insert(const value_type& x);
+
++Effects: Inserts+ +x
into themulti_index_container
to which +the index belongs if ++
+Returns: The return value is a pair- the index is non-unique OR no other element exists with + equivalent key,
+- AND insertion is allowed by all other indices of the +
+multi_index_container
.p
.p.second
+istrue
if and only if insertion took place. On successful insertion, +p.first
points to the element inserted; otherwise,p.first
+points to an element that caused the insertion to be banned. Note that more than +one element can be causing insertion not to be allowed.
+Complexity:O(I(n))
.
+Exception safety: Strong.
+
iterator insert(iterator position,const value_type& x);
+
++Requires:+ +position
is a valid iterator of the index. +Effects: Insertsx
into themulti_index_container
to which +the index belongs if ++
+- the index is non-unique OR no other element exists with + equivalent key,
+- AND insertion is allowed by all other indices of the +
+multi_index_container
.position
is used as a hint to improve the efficiency of the +operation.
+Returns: On successful insertion, an iterator to the newly inserted +element. Otherwise, an iterator to an element that caused the insertion to be +banned. Note that more than one element can be causing insertion not to be +allowed.
+Complexity:O(H(n))
.
+Exception safety: Strong.
+
template<typename InputIterator>
+void insert(InputIterator first,InputIterator last);
+
++Requires:+ +InputIterator
is a model of + +Input Iterator
over elements of type +value_type
or a type convertible tovalue_type
. +first
andlast
are not iterators into any +index of themulti_index_container
to which this index belongs. +last
is reachable fromfirst
. +Effects: ++Complexity:+iterator hint=end(); +while(first!=last)hint=insert(hint,*first++); +O(m*H(n+m))
, where +m
is the number of elements in [first
, +last
).
+Exception safety: Basic.
+
void erase(iterator position);
+
++Requires:+ +position
is a valid dereferenceable iterator +of the index. +Effects: Deletes the element pointed to byposition
.
+Complexity:O(D(n))
.
+Exception safety:nothrow
.
+
size_type erase(const key_type& x);
+
++Effects: Deletes the elements with key equivalent to+ +x
.
+Returns: Number of elements deleted.
+Complexity:O(log(n) + m*D(n))
, wherem
is +the number of elements deleted.
+Exception safety:nothrow
.
+
void erase(iterator first,iterator last);
+
++Requires: [+ +first
,last
) is a valid +range of the index.
+Effects: Deletes the elements in [first
,last
).
+Complexity:O(log(n) + m*D(n))
, wherem
is +the number of elements in [first
,last
).
+Exception safety:nothrow
.
+
bool replace(iterator position,const value_type& x);
+
++Requires:+ + +position
is a valid dereferenceable iterator +of the index. +Effects: Assigns the valuex
to the element pointed +to byposition
into themulti_index_container
to which +the index belongs if, for the valuex
++
+Postconditions: Validity of- the index is non-unique OR no other element exists + (except possibly
+*position
) with equivalent key,- AND replacing is allowed by all other indices of the +
+multi_index_container
.position
is preserved +in all cases.
+Returns:true
if the replacement took place, +false
otherwise.
+Complexity:O(R(n))
.
+Exception safety: Strong. If an exception is thrown by some +user-provided operation themulti_index_container
to which the index +belongs remains in its original state. +
template<typename Modifier> bool modify(iterator position,Modifier mod);
+
++Requires:+ + +Modifier
is a model of + +Unary Function
accepting arguments of type +value_type&
.position
is a valid dereferenceable +iterator of the index. +Effects: Callsmod(e)
wheree
is the element +pointed to byposition
and rearranges*position
into +all the indices of themulti_index_container
. Rearrangement is successful if ++
+If the rearrangement fails, the element is erased.- the index is non-unique OR no other element exists + with equivalent key,
+- AND rearrangement is allowed by all other indices of the +
+multi_index_container
.
+Postconditions: Validity ofposition
is preserved if the +operation succeeds.
+Returns:true
if the operation succeeded,false
+otherwise.
+Complexity:O(M(n))
.
+Exception safety: Basic. If an exception is thrown by some +user-provided operation (except possiblymod
), then +the element pointed to byposition
is erased. +
template<typename Modifier> bool modify_key(iterator position,Modifier mod);
+
++Requires:+ +key_from_value
is a read/write +Key Extractor
+fromvalue_type
.Modifier
is a model of + +Unary Function
accepting arguments of type +key_type&
.position
is a valid dereferenceable +iterator of the index. +Effects: Callsmod(k)
wherek
is the key +obtained by the internalKeyFromValue
object of the index from +the element pointed to byposition
, and rearranges +*position
into all the indices of themulti_index_container
. +Rearrangement is successful if ++
+If the rearrangement fails, the element is erased.- the index is non-unique OR no other element exists + with equivalent key,
+- AND rearrangement is allowed by all other indices of the +
+multi_index_container
.
+Postconditions:Validity ofposition
is preserved if +the operation succeeds.
+Returns:true
if the operation succeeded,false
+otherwise.
+Complexity:O(M(n))
.
+Exception safety: Basic. If an exception is thrown by some +user-provided operation (except possiblymod
), then +the element pointed to byposition
is erased. +
Apart from standard key_comp
and value_comp
,
+ordered indices have a member function for retrieving the internal key extractor
+used.
+
key_from_value key_extractor()const;
+
++Returns a copy of the+ +key_from_value
object used to construct +the index.
+Complexity: Constant. +
+Ordered indices provide the full lookup functionality required by
+
+Sorted Associative Containers
and
+
+Unique Associative Containers
, namely find
,
+count
, lower_bound
, upper_bound
+and equal_range
. Additionally, these member functions are
+templatized to allow for non-standard arguments, so extending
+the types of search operations allowed. The kind of arguments permissible
+when invoking the lookup member functions is defined by the following
+concept.
+
+Consider a
+
+Strict Weak Ordering
Compare
over values
+of type Key
. A pair of types (CompatibleKey
,
+CompatibleCompare
) is said to be a compatible extension
+of Compare
if
+
CompatibleCompare
is a
+
+ Binary Predicate
over (Key
,
+ CompatibleKey
),CompatibleCompare
is a
+
+ Binary Predicate
over (CompatibleKey
,
+ Key
),c_comp(ck,k1)
then !c_comp(k1,ck)
,!c_comp(ck,k1)
and !comp(k1,k2)
then
+ !c_comp(ck,k2)
,!c_comp(k1,ck)
and !comp(k2,k1)
then
+ !c_comp(k2,ck)
,c_comp
of type CompatibleCompare
,
+comp
of type Compare
, ck
of type
+CompatibleKey
and k1
, k2
of type
+Key
.
+
+
+
+
+Additionally, a type CompatibleKey
is said to be a
+compatible key of Compare
if (CompatibleKey
,
+Compare
) is a compatible extension of Compare
.
+This implies that Compare
, as well as being a strict
+weak ordering, accepts arguments of type CompatibleKey
,
+which usually means it has several overloads of operator()
.
+
+In the context of a compatible extension or a compatible key, the expressions +"equivalent", "less than" and "greater than" take on their obvious +interpretations. +
+ +template<typename CompatibleKey> const_iterator find(const CompatibleKey& x)const;
+
+
++Requires:+ +CompatibleKey
is a compatible key of +key_compare
. +Effects: Returns a pointer to an element whose key is equivalent to +x
, orend()
if such an element does not exist.
+Complexity:O(log(n))
.
+
template<typename CompatibleKey,typename CompatibleCompare>
+const_iterator find(const CompatibleKey& x,const CompatibleCompare& comp)const;
+
+
++Requires: (+ +CompatibleKey
,CompatibleCompare
) +is a compatible extension ofkey_compare
. +Effects: Returns a pointer to an element whose key is equivalent to +x
, orend()
if such an element does not exist.
+Complexity:O(log(n))
.
+
template<typename CompatibleKey> size_type
+count(const CompatibleKey& x)const;
+
+
++Requires:+ +CompatibleKey
is a compatible key of +key_compare
. +Effects: Returns the number of elements with key equivalent tox
.
+Complexity:O(log(n) + count(x))
.
+
template<typename CompatibleKey,typename CompatibleCompare>
+size_type count(const CompatibleKey& x,const CompatibleCompare& comp)const;
+
+
++Requires: (+ +CompatibleKey
,CompatibleCompare
) +is a compatible extension ofkey_compare
. +Effects: Returns the number of elements with key equivalent tox
.
+Complexity:O(log(n) + count(x,comp))
.
+
template<typename CompatibleKey>
+const_iterator lower_bound(const CompatibleKey& x)const;
+
+
++Requires:+ +CompatibleKey
is a compatible key of +key_compare
. +Effects: Returns an iterator pointing to the first element with +key not less thanx
, orend()
if such an element does +not exist.
+Complexity:O(log(n))
.
+
template<typename CompatibleKey,typename CompatibleCompare>
+const_iterator lower_bound(const CompatibleKey& x,const CompatibleCompare& comp)const;
+
+
++Requires: (+ +CompatibleKey
,CompatibleCompare
) +is a compatible extension ofkey_compare
. +Effects: Returns an iterator pointing to the first element with +key not less thanx
, orend()
if such an element does +not exist.
+Complexity:O(log(n))
.
+
template<typename CompatibleKey>
+const_iterator upper_bound(const CompatibleKey& x)const;
+
+
++Requires:+ +CompatibleKey
is a compatible key of +key_compare
. +Effects: Returns an iterator pointing to the first element with +key greater thanx
, orend()
if such an element does +not exist.
+Complexity:O(log(n))
.
+
template<typename CompatibleKey,typename CompatibleCompare>
+const_iterator upper_bound(const CompatibleKey& x,const CompatibleCompare& comp)const;
+
+
++Requires: (+ +CompatibleKey
,CompatibleCompare
) +is a compatible extension ofkey_compare
. +Effects: Returns an iterator pointing to the first element with +key greater thanx
, orend()
if such an element does +not exist.
+Complexity:O(log(n))
.
+
template<typename CompatibleKey>
+std::pair<const_iterator,const_iterator> equal_range(
+ const CompatibleKey& x)const;
+
+
++Requires:+ +CompatibleKey
is a compatible key of +key_compare
. +Effects: Equivalent tomake_pair(lower_bound(x),upper_bound(x))
.
+Complexity:O(log(n))
.
+
template<typename CompatibleKey,typename CompatibleCompare>
+std::pair<const_iterator,const_iterator> equal_range(
+ const CompatibleKey& x,const CompatibleCompare& comp)const;
+
+
++Requires: (+ + +CompatibleKey
,CompatibleCompare
) +is a compatible extension ofkey_compare
. +Effects: Equivalent to +make_pair(lower_bound(x,comp),upper_bound(x,comp))
.
+Complexity:O(log(n))
.
+
+The member function range
is not defined for sorted associative
+containers, but ordered indices provide it as a convenient utility. A range
+or interval is defined by two conditions for the lower and upper bounds, which
+are modeled after the following concepts.
+
+Consider a
+
+Strict Weak Ordering
Compare
over values
+of type Key
. A type LowerBounder
is said to be
+a lower bounder of Compare
if
+
LowerBounder
is a
+
+ Predicate
over Key
,lower(k1)
and !comp(k2,k1)
then
+ lower(k2)
,lower
of type LowerBounder
,
+comp
of type Compare
, and k1
,
+k2
of type Key
. Similarly, an upper bounder
+is a type UpperBounder
such that
+UpperBounder
is a
+
+ Predicate
over Key
,upper(k1)
and !comp(k1,k2)
then
+ upper(k2)
,upper
of type UpperBounder
,
+comp
of type Compare
, and k1
,
+k2
of type Key
.
+
+
+template<typename LowerBounder,typename UpperBounder>
+std::pair<const_iterator,const_iterator> range(
+ LowerBounder lower,UpperBounder upper)const;
+
+
++Requires:+ +LowerBounder
andUpperBounder
are +a lower and upper bounder ofkey_compare
, respectively. +Effects: Returns a pair of iterators pointing to the beginning and one +past the end of the subsequence of elements satisfyinglower
and +upper
simultaneously. If no such elements exist, the iterators +both point to the first element satisfyinglower
, or else +are equal toend()
if this latter element does not exist.
+Complexity:O(log(n))
.
+Variants: In place oflower
orupper
(or both), +the singular valueboost::multi_index::unbounded
can be +provided. This acts as a predicate which all values of typekey_type
+satisfy.
+
Revised May 7th 2004
+ +Copyright © 2003-2004 Joaquín M López Muñoz. +Use, modification, and distribution are subject to the Boost Software +License, Version 1.0. (See accompanying file +LICENSE_1_0.txt or copy at +www.boost.org/LICENSE_1_0.txt) +
+ + + diff --git a/doc/reference/seq_indices.html b/doc/reference/seq_indices.html new file mode 100644 index 0000000..6df02e6 --- /dev/null +++ b/doc/reference/seq_indices.html @@ -0,0 +1,837 @@ + + + + + +"boost/multi_index/sequenced_index_fwd.hpp"
synopsis"boost/multi_index/sequenced_index.hpp"
synopsis
+
+ "boost/multi_index/sequenced_index_fwd.hpp"
synopsis+ ++namespace boost{ + +namespace multi_index{ + +// sequenced index specifier + +template<typename TagList=tag<> > struct sequenced; + +// indices + +namespace detail{ + +template<implementation defined> class index class name implementation defined; + +} // namespace boost::multi_index::detail + +} // namespace boost::multi_index + +} // namespace boost +
+sequenced_index_fwd.hpp
provides forward declarations for the
+sequenced
index specifier and
+its associated sequenced index class.
+
"boost/multi_index/sequenced_index.hpp"
synopsis+ ++namespace boost{ + +namespace multi_index{ + +// sequenced index specifier + +template<typename TagList=tag<> > struct sequenced; + +// indices + +namespace detail{ + +template<implementation defined> class index class name implementation defined; + +// index comparison: + +// OP is any of ==,<,!=,>,>=,<= + +template<arg set 1,arg set 2> +bool operator OP( + const index class name<arg set 1>& x,const index class name<arg set 2>& y); + +// index specialized algorithms: + +template<implementation defined> +void swap(index class name& x,index class name& y); + +} // namespace boost::multi_index::detail + +} // namespace boost::multi_index + +} // namespace boost +
sequenced
index specifier
++This index specifier allows for insertion of a sequenced +index.
+ ++ ++template<typename TagList=tag<> > struct sequenced; +
If provided, TagList
must be an instantiation of
+tag
.
+
+Sequenced indices are modeled after the semantics of a bidirectional list
+like std::list
. Elements in a sequenced index are by default
+sorted according to their order of insertion: this means that new elements
+inserted through a different index of the multi_index_container
are appended
+to the end of the sequenced index. Additionally, the index allows for free
+reordering of elements in the same vein as std::list
does.
+
+There are a number of differences with respect to std::lists
:
+
Assignable
(like any other index.)std::list
, insertions into a sequenced index
+ may fail due to clashings with other indices. This alters the semantics
+ of the operations provided with respect to their analogues in
+ std::list
.
+ replace
and
+ modify
member functions.
+ Reversible Container
,
+
+Front Insertion Sequence
and
+
+Back Insertion Sequence
. We only provide descriptions
+of those types and operations that are that are either not present in the
+concepts modeled or do not exactly conform to the requirements for these
+types of containers.
+
+
++ ++namespace boost{ + +namespace multi_index{ + +namespace detail{ + +template<implementation defined: dependent on types Value, Allocator, TagList> +class name is implementation defined +{ +public: + // types: + + typedef typename node_type::value_type value_type; + typedef tuples::null_type ctor_args; + typedef typename Allocator allocator_type; + typedef typename allocator_type::reference reference; + typedef typename allocator_type::const_reference const_reference; + typedef implementation defined iterator; + typedef implementation defined const_iterator; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef typename allocator_type::pointer pointer; + typedef typename allocator_type::const_pointer const_pointer; + typedef equivalent to + std::reverse_iterator<iterator> reverse_iterator; + typedef equivalent to + std::reverse_iterator<const_iterator> const_reverse_iterator; + + // construct/copy/destroy: + + index class name& operator=(const index class name& x); + + template <class InputIterator> + void assign(InputIterator first,InputIterator last); + void assign(size_type n,const value_type& value); + + allocator_type get_allocator()const; + + // iterators: + + iterator begin(); + const_iterator begin()const; + iterator end(); + const_iterator end()const; + reverse_iterator rbegin(); + const_reverse_iterator rbegin()const; + reverse_iterator rend(); + const_reverse_iterator rend()const; + + // capacity: + + bool empty()const; + size_type size()const; + size_type max_size()const; + + void resize(size_type n,const value_type& x=value_type()); + + // access: + + const_reference front()const; + const_reference back()const; + + // modifiers: + + std::pair<iterator,bool> push_front(const value_type& x); + void pop_front(); + std::pair<iterator,bool> push_back(const value_type& x); + void pop_back(); + + std::pair<iterator,bool> insert(iterator position,const value_type& x); + void insert(iterator position,size_type n,const value_type& x); + template<typename InputIterator> + void insert(iterator position,InputIterator first,InputIterator last); + + void erase(iterator position); + void erase(iterator first,iterator last); + + bool replace(iterator position,const value_type& x); + template<typename Modifier> bool modify(iterator position,Modifier mod); + + void swap(index class name& x); + + void clear(); + + // list operations: + + void splice(iterator position,index class name& x); + void splice(iterator position,index class name& x,iterator i); + void splice( + iterator position,index class name& x,iterator first,iterator last); + + void remove(const value_type& value); + template<typename Predicate> void remove_if(Predicate pred); + + void ordered_unique(); + template <class BinaryPredicate> + void ordered_unique(BinaryPredicate binary_pred); + + void merge(index class name& x); + template <typename Compare> void merge(index class name& x,Compare comp); + + void sort(); + template <typename Compare> void sort(Compare comp); + + void reverse(); + + // relocate operations: + + void relocate(iterator position,iterator i); + void relocate(iterator position,iterator first,iterator last); +} + +// index comparison: + +template<arg set 1,arg set 2> +bool operator==( + const index class name<arg set 1>& x, + const index class name<arg set 2>& y) +{ + return x.size()==y.size()&&std::equal(x.begin(),x.end(),y.begin()); +} + +template<arg set 1,arg set 2> +bool operator<( + const index class name<arg set 1>& x, + const index class name<arg set 2>& y) +{ + return std::lexicographical_compare(x.begin(),x.end(),y.begin(),y.end()); +} + +template<arg set 1,arg set 2> +bool operator!=( + const index class name<arg set 1>& x, + const index class name<arg set 2>& y) +{ + return !(x==y); +} + +template<arg set 1,arg set 2> +bool operator>( + const index class name<arg set 1>& x + ,const index class name<arg set 2>& y) +{ + return y<x; +} + +template<arg set 1,arg set 2> +bool operator>=( + const index class name<arg set 1>& x, + const index class name<arg set 2>& y) +{ + return !(x<y); +} + +template<arg set 1,arg set 2> +bool operator<=( + const index class name<arg set 1>& x, + const index class name<arg set 2>& y) +{ + return !(x>y); +} + +// index specialized algorithms: + +template<implementation defined> +void swap(index class name& x,index class name& y); + +} // namespace boost::multi_index::detail + +} // namespace boost::multi_index + +} // namespace boost +
+Here and in the descriptions of operations of sequenced indices, we adopt the +scheme outlined in the +complexity signature +section. The complexity signature of sequenced indices is: +
c(n)=n*log(n)
,i(n)=1
(constant),h(n)=1
(constant),d(n)=1
(constant),r(n)=1
(constant),m(n)=1
(constant).Sequenced indices are instantiated internally to multi_index_container
+and specified by means of
+indexed_by
with the sequenced
+index specifier. Instantiations are dependent on the following types:
+
Value
from multi_index_container
,Allocator
from multi_index_container
,TagList
from the index specifier (if provided).TagList
must be an instantiation of
+tag
.
+
+
++As explained in the index +concepts section, indices do not have public constructors or destructors. +Assignment, on the other hand, is provided. +
+ +index class name& operator=(const index class name& x);
+
++Effects: ++ ++where+a=b; +a
andb
are themulti_index_container
+objects to which*this
andx
belongs, respectively.
+Returns:*this
.
+
template <class InputIterator>
+void assign(InputIterator first,InputIterator last);
+
++Requires:+ +InputIterator
is a model of + +Input Iterator
over elements of type +value_type
or a type convertible tovalue_type
. +first
andlast
are not iterators into any +index of themulti_index_container
to which this index belongs. +last
is reachable fromfirst
. +Effects: +++clear(); +insert(end(),first,last); +
void assign(size_type n,const value_type& value);
+
++Effects: ++ +++clear(); +for(size_type i=0;i<n;++n)push_back(v); +
void resize(size_type n,const value_type& x=value_type());
+
++Effects: ++ ++Note: If an expansion is requested, the size of the index is not guaranteed +to be+if(n>size())insert(end(),n-size(),x); +else if(n<size())erase(begin()+n,end()); +n
after this operation (other indices may ban insertions.) +
std::pair<iterator,bool> push_front(const value_type& x);
+
++Effects: Inserts+ +x
at the beginning of the sequence if +no other index of themulti_index_container
bans the insertion.
+Returns: The return value is a pairp
.p.second
+istrue
if and only if insertion took place. On successful +insertion,p.first
points to the element inserted; otherwise, +p.first
points to an element that caused the insertion to be banned. +Note that more than one element can be causing insertion not to be allowed.
+Complexity:O(I(n))
.
+Exception safety: Strong. +
std::pair<iterator,bool> push_back(const value_type& x);
+
++Effects: Inserts+ +x
at the end of the sequence if +no other index of themulti_index_container
bans the insertion.
+Returns: The return value is a pairp
.p.second
+istrue
if and only if insertion took place. On successful +insertion,p.first
points to the element inserted; otherwise, +p.first
points to an element that caused the insertion to be banned. +Note that more than one element can be causing insertion not to be allowed.
+Complexity:O(I(n))
.
+Exception safety: Strong. +
iterator insert(iterator position,const value_type& x);
+
++Requires:+ +position
is a valid iterator of the index. +Effects: Insertsx
beforeposition
if insertion +is allowed by all other indices of themulti_index_container
.
+Returns: On successful insertion, an iterator to the newly inserted +element. Otherwise, an iterator to an element that caused the insertion to be +banned. Note that more than one element can be causing insertion not to be +allowed.
+Complexity:O(I(n))
.
+Exception safety: Strong. +
void insert(iterator position,size_type n,const value_type& x);
+
++Requires:+ +position
is a valid iterator of the index. +Effects: +++for(size_type i=0;i<n;++i)insert(position,x); +
template<typename InputIterator>
+void insert(iterator position,InputIterator first,InputIterator last);
+
++Requires:+ +position
is a valid iterator of the index. +InputIterator
is a model of + +Input Iterator
over elements of type +value_type
or a type convertible tovalue_type
. +first
andlast
are not iterators into any +index of themulti_index_container
to which this index belongs. +last
is reachable fromfirst
. +Effects: ++Complexity:+while(first!=last)insert(position,*first++); +O(m*I(n+m))
, wherem
is the +number of elements in [first
,last
).
+Exception safety: Basic. +
void erase(iterator position);
+
++Requires:+ +position
is a valid dereferenceable iterator +of the index. +Effects: Deletes the element pointed to byposition
.
+Complexity:O(D(n))
.
+Exception safety:nothrow
.
+
void erase(iterator first,iterator last);
+
++Requires: [+ +first
,last
) is a valid +range of the index.
+Effects: Deletes the elements in [first
,last
).
+Complexity:O(m*D(n))
, wherem
is +the number of elements in [first
,last
).
+Exception safety:nothrow
.
+
bool replace(iterator position,const value_type& x);
+
++Requires:+ + +position
is a valid dereferenceable iterator +of the index. +Effects: Assigns the valuex
to the element pointed +to byposition
into themulti_index_container
to which +the index belongs if replacing is allowed by all other indices of the +multi_index_container
.
+Postconditions: Validity ofposition
is preserved +in all cases.
+Returns:true
if the replacement took place, +false
otherwise.
+Complexity:O(R(n))
.
+Exception safety: Strong. If an exception is thrown by some +user-provided operation themulti_index_container
to which the index +belongs remains in its original state. +
template<typename Modifier> bool modify(iterator position,Modifier mod);
+
++Requires:+ +Modifier
is a model of + +Unary Function
accepting arguments of type +value_type&
.position
is a valid dereferenceable +iterator of the index. +Effects: Callsmod(e)
wheree
is the element +pointed to byposition
and rearranges*position
into +all the indices of themulti_index_container
. Rearrangement on sequenced +indices does not change the position of the element with respect to the index; +rearrangement on other indices may or might not suceed. If the rearrangement +fails, the element is erased.
+Postconditions: Validity ofposition
is preserved if the +operation succeeds.
+Returns:true
if the operation succeeded,false
+otherwise.
+Complexity:O(M(n))
.
+Exception safety: Basic. If an exception is thrown by some +user-provided operation (except possiblymod
), then +the element pointed to byposition
is erased. +
+Sequenced indices provides the full set of list operations provided by
+std::list
; the semantics of these member functions, however,
+differ from that of std::list
in some cases as insertions
+might not succeed due to banning by other indices. Similarly, the complexity
+of the operations may depend on the other indices belonging to the
+same multi_index_container
.
+
void splice(iterator position,index class name& x);
+
++Requires:+ +position
is a valid iterator of the index. +&x!=this
. +Effects: Inserts the contents ofx
beforeposition
, +in the same order as they were inx
. Those elements succesfully +inserted are erased fromx
.
+Complexity:O(x.size()*I(n+x.size()) + x.size()*D(x.size()))
.
+Exception safety: Basic.
+
void splice(iterator position,index class name& x,iterator i);
+
++Requires:+ +position
is a valid iterator of the index. +i
is a valid dereferenceable iteratorx
.
+Effects: Inserts the element pointed to byi
before +position
: if insertion is succesful, the element is erased from +x
. In the special case&x==this
, no copy or +deletion is performed, and the operation is always succesful. If +position==i
, no operation is performed.
+Postconditions: If&x==this
, no iterator or reference +is invalidated.
+Complexity: If&x==this
, constant; otherwise +O(I(n) + D(n))
.
+Exception safety: If&x==this
,nothrow
; +otherwise, strong.
+
void splice(iterator position,index class name& x,iterator first,iterator last);
+
++Requires:+ +position
is a valid iterator of the index. +first
andlast
are valid iterators ofx
. +last
is reachable fromfirst
.position
+is not in the range [first
,last
).
+Effects: For each element in the range [first
,last
), +insertion is tried beforeposition
; if the operation is succesful, +the element is erased fromx
. In the special case +&x==this
, no copy or deletion is performed, and insertions are +always succesful.
+Postconditions: If&x==this
, no iterator or reference +is invalidated.
+Complexity: If&x==this
, constant; otherwise +O(m*I(n+m) + m*D(x.size()))
wherem
is the number +of elements in [first
,last
).
+Exception safety: If&x==this
,nothrow
; +otherwise, basic.
+
void remove(const value_type& value);
+
++Effects: Erases all elements of the index which compare equal to ++ +value
.
+Complexity:O(n + m*D(n))
, wherem
+is the number of elements erased.
+Exception safety: Basic. +
template<typename Predicate> void remove_if(Predicate pred);
+
++Effects: Erases all elements+ +x
of the index for which +pred(x)
holds..
+Complexity:O(n + m*D(n))
, wherem
+is the number of elements erased.
+Exception safety: Basic. +
void unique();
+
++Effects: Eliminates all but the first element from every consecutive +group of equal elements referred to by the iterator+ +i
in the range +[first+1
,last
) for which*i==*(i-1)
.
+Complexity:O(n + m*D(n))
, wherem
+is the number of elements erased.
+Exception safety: Basic. +
template <class BinaryPredicate> void unique(BinaryPredicate binary_pred);
+
++Effects: Eliminates all but the first element from every consecutive +group of elements referred to by the iterator+ +i
in the range +[first+1
,last
) for which +binary_pred(*i,*(i-1))
holds.
+Complexity:O(n + m*D(n))
, wherem
+is the number of elements erased.
+Exception safety: Basic. +
void merge(index class name& x);
+
++Requires:+ +std::less<value_type>
is a + +Strict Weak Ordering
overvalue_type
. +Both the index andx
are sorted according to +std::less<value_type>
.
+Effects: Attempts to insert every element ofx
into the +corresponding position of the index (according to the order). Elements +successfully inserted are erased fromx
. The resulting sequence +is stable, i.e. equivalent elements of either container preserve their +relative position. In the special case&x==this
, no operation +is performed.
+Postconditions: Elements in the index and remaining elements in +x
are sorted. +Validity of iterators to the index and of non-erased elements ofx
+references is preserved.
+Complexity: If&x==this
, constant; otherwise +O(n + x.size()*I(n+x.size()) + x.size()*D(x.size()))
.
+Exception safety: If&x==this
,nothrow
; +otherwise, basic.
+
template <typename Compare> void merge(index class name& x,Compare comp);
+
++Requires:+ +Compare
is a + +Strict Weak Ordering
overvalue_type
. +Both the index andx
are sorted according tocomp
.
+Effects: Attempts to insert every element ofx
into the +corresponding position of the index (according tocomp
). +Elements successfully inserted are erased fromx
. The resulting +sequence is stable, i.e. equivalent elements of either container preserve +their relative position. In the special case&x==this
, no +operation is performed.
+Postconditions: Elements in the index and remaining elements in +x
are sorted according tocomp
. +Validity of iterators to the index and of non-erased elements ofx
+references is preserved.
+Complexity: If&x==this
, constant; otherwise +O(n + x.size()*I(n+x.size()) + x.size()*D(x.size()))
.
+Exception safety: If&x==this
,nothrow
; +otherwise, basic.
+
void sort();
+
++Requires:+ +std::less<value_type>
is a + +Strict Weak Ordering
overvalue_type
.
+Effects: Sorts the index according to +std::less<value_type>
. The sorting is stable, i.e. +equivalent elements preserve their relative position.
+Postconditions: Validity of iterators and references is preserved.
+Complexity:O(n*log(n))
.
+Exception safety:nothrow
if +std::less<value_type>
does not throw; otherwise, basic. +
template <typename Compare> void sort(Compare comp);
+
++Requires:+ +Compare
is a + +Strict Weak Ordering
overvalue_type
.
+Effects: Sorts the index according tocomp
. The sorting +is stable, i.e. equivalent elements preserve their relative position.
+Postconditions: Validity of iterators and references is preserved.
+Complexity:O(n*log(n))
.
+Exception safety:nothrow
ifcomp
does +not throw; otherwise, basic. +
void reverse();
+
++Effects: Reverses the order of the elements in the index.+ +
+Postconditions: Validity of iterators and references is preserved.
+Complexity:O(n)
.
+Exception safety:nothrow
. +
+Sequenced indices provide some convenience member functions without
+counterparts in std::list
. These operations are aimed at
+improving the usability of sequenced indices in points where
+the support offered by standard list operations is insufficient or
+difficult to use.
+
void relocate(iterator position,iterator i);
+
++Requires:+ +position
is a valid iterator of the index. +i
is a valid dereferenceable iterator of the index.
+Effects: Inserts the element pointed to byi
before +position
. Ifposition==i
, no operation is +performed.
+Postconditions: No iterator or reference is invalidated.
+Complexity: Constant.
+Exception safety:nothrow
.
+
void relocate(iterator position,iterator first,iterator last);
+
++Requires:+ +position
is a valid iterator of the index. +first
andlast
are valid iterators of the index. +last
is reachable fromfirst
.position
+is not in the range [first
,last
).
+Effects: The range of elements [first
,last
) +is repositioned just beforeposition
.
+Postconditions: No iterator or reference is invalidated.
+Complexity: Constant.
+Exception safety:nothrow
.
+
Revised May 7th 2004
+ +Copyright © 2003-2004 Joaquín M López Muñoz. +Use, modification, and distribution are subject to the Boost Software +License, Version 1.0. (See accompanying file +LICENSE_1_0.txt or copy at +www.boost.org/LICENSE_1_0.txt) +
+ + + diff --git a/doc/style.css b/doc/style.css new file mode 100644 index 0000000..3e4034b --- /dev/null +++ b/doc/style.css @@ -0,0 +1,48 @@ +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;} diff --git a/doc/tests.html b/doc/tests.html new file mode 100644 index 0000000..ec8dd5c --- /dev/null +++ b/doc/tests.html @@ -0,0 +1,146 @@ + + + + + ++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. +
+ ++
Program | +Description | +
---|---|
test_basic.cpp |
+ Simple program along the lines of the employees example studied in the + tutorial. | +
test_capacity.cpp |
+ empty , size and (sequenced indices only)
+ resize . |
+
test_comparison.cpp |
+ Comparison between indices. | +
test_composite_key.cpp |
+ composite_key and composite_key_compare . |
+
test_conv_iterators.cpp |
+ Checks convertibility of constant to non-constant iterators. | +
test_copy_assignment.cpp |
+ Various forms of assignment: copy, operator = , insertion,
+ (sequenced indices only) assign .
+ |
test_iterators.cpp |
+ Constant and non-constant iterators and their reverse variants. | +
test_key_extractors.cpp |
+ Covers all use cases of key extractors shipped with the library. | +
test_list_ops.cpp |
+ List-like operations particular to sequenced indices. | +
test_modifiers.cpp |
+ Checks the family of insertion and erasing operations. | +
test_mpl_ops.cpp |
+ Shows how to take advantage of mpl_index_list in a
+ metaprogram. |
+
test_projection.cpp |
+ Projection of iterators among indices. | +
test_range.cpp |
+ Exercises the range facility (ordered indices only). |
+
test_safe_mode.cpp |
+ Comprehensive coverage of all conditions checked in safe mode. | +
test_set_ops.cpp |
+ Set-like operations particular to ordered indices. | +
test_special_list_ops.cpp |
+ Convenience functions of sequenced indices not present in
+ std::list . |
+
test_special_set_ops.cpp |
+ Checks special lookup operations using compatible sorting criteria. | +
test_update.cpp |
+ replace , modify and modify_key . |
+
Revised May 7th 2004
+ +Copyright © 2003-2004 Joaquín M López Muñoz. +Use, modification, and distribution are subject to the Boost Software +License, Version 1.0. (See accompanying file +LICENSE_1_0.txt or copy at +www.boost.org/LICENSE_1_0.txt) +
+ + + diff --git a/doc/tutorial.html b/doc/tutorial.html new file mode 100644 index 0000000..729d754 --- /dev/null +++ b/doc/tutorial.html @@ -0,0 +1,1260 @@ + + + + + +
+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 std::set
maintains the elements ordered
+by a specified sorting criterium, std::list
allows for free
+positioning of elements along a linear sequence, and so on.
+
+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
+multi_index_container
s comprised of one or more indices 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
+multi_index_container
instantiation be specified at compile time: this
+gives ample room for static type checking and code optimization.
+
+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. multi_index_container
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.
+
+
+Fig. 1: Diagram of a multi_index_container
with three indices.
+
+The figure above depicts a multi_index_container
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 std::list
. 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 std::set
s or std::list
s. Insertion of an
+element through one given index will only succeed if the uniqueness constraints of all
+indices are met.
+
+All the types of Boost.MultiIndex reside in namespace ::boost::multi_index
.
+Additionaly, the main class template multi_index_container
and global functions
+get
and project
are lifted to namespace ::boost
+by means of using
declarations. For brevity of exposition, the fragments
+of code in the documentation are written as if the following declarations were in effect:
+
+ ++using namespace ::boost; +using namespace ::boost::multi_index; +
+We introduce the main concepts of Boost.MultiIndex through the study of +two typical use cases. +
+ ++STL sets and multisets are varying-length containers where elements are efficiently +sorted according to a given comparison predicate. These container classes fall short +of functionality when the programmer wishes to efficiently sort and look up the elements +following a different sorting criterium. Consider for instance: +
+ ++ ++struct employee +{ + int id; + std::string name; + + employee(int id,std::string name):id(id),name(name){} + + bool operator<(const employee& e)const{return id<e.id;} +}; +
The fact that IDs are unique to each employee is reflected by the way
+operator<
is defined, so a natural data structure for storing of
+employee
s is just a std::set<employee>
. Now,
+if one wishes to print out a listing of all employees in alphabetical order, available
+solutions may have disadvantages either in terms of storage space, complexity or ease
+of maintenance:
+
employee::name
.
+
+Boost.MultiIndex features ordered indices, which
+sort the elements according to a particular key, and are designed to help programmers
+in need of sequences of elements for which more than one sorting criteria are
+relevant. We do so by defining a multi_index_container
+instantiation composed of several ordered indices: each index, viewed in isolation,
+behaves much as an ordered std::set
(or std::multiset
), whilst
+the overall integrity of the entire data structure is preserved. Our example problem
+thus can be solved with Boost.MultiIndex as follows:
+
+ ++// define a multiply indexed set with indices by id and name +typedef multi_index_container< + employee, + indexed_by< + // sort by employee::operator< + ordered_unique<identity<employee> >, + + // sort by less<string> on name + ordered_non_unique<member<employee,std::string,&employee::name> > + > +> employee_set; + +void print_out_by_name(const employee_set& es) +{ + // get a view to index #1(name) + const employee_set::nth_index<1>::type& name_index=es.get<1>(); + // use name_index as a regular std::set + std::copy( + name_index.begin(),name_index.end(), + std::ostream_iterator<employee>(std::cout)); +} +
+Instead of a single comparison predicate type, as it happens for STL associative
+containers, multi_index_container
is passed a typelist of index
+specifications (indexed_by
), each one inducing the corresponding index.
+Indices are accessed via
+get
<N>()
+where N ranges between 0 and the number of comparison
+predicates minus one. The functionality of index #0 can be accessed directly from an
+multi_index_container
object without using get<0>()
: for instance,
+es.begin()
is equivalent to es.get<0>().begin()
.
+
+This study case allows us to introduce so-called +sequenced indices, and how they +interact with ordered indices to construct powerful containers. Suppose +we have a text parsed into words and stored in a list like this: +
+ ++ ++typedef std::list<std::string> text_container; + +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 list +text_container tc; +boost::tokenizer<boost::char_separator<char> > tok + (text,boost::char_separator<char>(" \t\n.,;:!?'\"-")); +std::copy(tok.begin(),tok.end(),std::back_inserter(tc)); +
+If we want to count the occurrences of a given word into the text we will resort
+to std::count
:
+
+ ++std::size_t occurrences(const std::string& word) +{ + return std::count(tc.begin(),tc.end(),word); +} +
+But this implementation of occurrences
performs in linear time, which
+could be unacceptable for large quantities of text. Similarly, other operations like
+deletion of selected words are just too costly to carry out on a
+std::list
:
+
+ ++void delete_word(const std::string& word) +{ + tc.remove(word); // scans the entire list looking for word +} +
+When performance is a concern, we will need an additional data structure that indexes
+the elements in tc
, presumably in alphabetical order. Boost.MultiIndex
+does precisely this through the combination of sequenced and ordered indices:
+
+ ++// define a multi_index_container with a list-like index and an ordered index +typedef multi_index_container< + std::string, + indexed_by< + sequenced<>, // list-like index + ordered_non_unique<identity<std::string> > // words by alphabetical order + > +> text_container; + +std::string text=... + +// feed the text into the list +text_container tc; +boost::tokenizer<boost::char_separator<char> > tok + (text,boost::char_separator<char>(" \t\n.,;:!?'\"-")); +std::copy(tok.begin(),tok.end(),std::back_inserter(tc)); +
+So far, the substitution of multi_index_container
for std::list
+does not show any advantage. The code for inserting the text into the container
+does not change as sequenced indices provide an interface similar to that of
+std::list
(no explicit access to this index through
+get<0>()
is needed as multi_index_container
inherits the
+functionality of index #0.) But the specification of an additional ordered index
+allows us to implement occurrences
and delete_word
+in a much more efficient manner:
+
+ ++std::size_t occurrences(const std::string& word) +{ + // get a view to index #1 + text_container::nth_index<1>::type& sorted_index=tc.get<1>(); + + // use sorted_index as a regular std::set + return sorted_index.count(word); +} + +void delete_word(const std::string& word) +{ + // get a view to index #1 + text_container::nth_index<1>::type& sorted_index=tc.get<1>(); + + // use sorted_index as a regular std::set + sorted_index.erase(word); +} +
+Now, occurrences
and delete_word
have logarithmic
+complexity. The programmer can use index #0 for accessing the text as with
+std::list
, and use index #1 when logarithmic lookup is needed.
+
+The indices of a multi_index_container
instantiation are specified by
+means of the
+indexed_by
construct. For instance, the instantiation
+
+ ++typedef multi_index_container< + employee, + indexed_by< + ordered_unique<identity<employee> >, + ordered_non_unique<member<employee,std::string,&employee::name> > + > +> employee_set; +
+is comprised of a unique ordered index and a +non-unique ordered index, while in +
+ ++ ++typedef multi_index_container< + std::string, + indexed_by< + sequenced<>, + ordered_non_unique<identity<std::string> > + > +> text_container; +
+we specifiy two indices, the first of sequenced type,
+the second a non-unique ordered index. In general, we
+can specify an arbitrary number of indices: each of the arguments of
+indexed_by
is called an
+index specifier.
+Depending on the type of index being specified, the corresponding specifier
+will need additional information: for instance, the specifiers ordered_unique
+and ordered_non_unique
are provided with a
+key extractor and an optional
+comparison predicate which jointly indicate
+how the sorting of elements will be performed.
+
+A multi_index_container
instantiation can be declared without supplying
+the indexed_by
part: in this case, default index values are taken
+so that the resulting type is equivalent to a regular std::set
.
+Concretely, the instantiation
+
+ ++multi_index_container<(element)> +
+is equivalent to +
+ ++ ++multi_index_container< + (element), + indexed_by< + ordered_unique<identity<(element)> > + > +> +
+In order to retrieve (a reference to) an index of a given multi_index_container
,
+the programmer must provide its order number, which is cumbersome and not very
+self-descriptive. Optionally, indices can be assigned tags (C++ types) that
+act as more convenient mnemonics. If provided, tags must be passed as the
+first parameter of the corresponding index specifier. The following is a revised version of
+employee_set
with inclusion of tags:
+
+ ++// tags +struct name{}; + +typedef multi_index_container< + employee, + indexed_by< + ordered_unique<identity<employee> >, + ordered_non_unique<tag<name>,member<employee,std::string,&employee::name> > + > +> employee_set; +
+Tags have to be passed inside the tag
construct. Any type can be
+used as a tag for an index, although in general one will choose names that are
+descriptive of the index they are associated with. The tagging mechanism allows
+us to write expressions like
+ ++typedef employee_set::index<name>::type employee_set_by_name; +employee_set_by_name::iterator it=es.get<name>().begin(); +
+If no tag is provided for an index (as is the case for index #0 of the previous
+example), access to that index can only be performed by number. Note the existence
+of two different typedef
s nth_index
and
+index
for referring to an index by number and by tag, respectively;
+for instance,
+
employee_set::nth_index<1>::type
is the type of
+ index #1,employee_set::index<name>::type
is the type of the index
+ tagged with name
(the same index #1 in this case.)get()
, on the other hand, is overloaded to serve both styles of access:
+
+
++ ++employee_set::index<name>::type& name_index=es.get<name>(); +employee_set::nth_index<1>::type& name_index2=es.get<1>(); // same index +
+Additionally, the tag
class template accepts several tags for one
+index, that we can use interchangeably: for instance, the specification of index #1
+in the previous example can be rewritten to hold two different tags
+name
and by_name
:
+
+ ++// tags +struct name{}; +struct by_name{}; + +typedef multi_index_container< + ... + ordered_non_unique< + tag<name,by_name>, + member<employee,std::string,&employee::name> + > + ... +> employee_set; +
+Currently, Boost.MultiIndex provides the following index types: +
std::set
s do and
+ provide a similar interface. There are unique and non-unique
+ variants: the former do not allow for duplicates, while the latter permit
+ them (like std::multiset
.)std::list
: they arrange the elements as if in a bidirectional
+ list.
+Ordered indices sort the elements in a multi_index_container
according
+to a specified key and an associated comparison predicate. These indices can
+be viewed as analogues of the standard container std::set
, and in fact
+they do replicate its interface, albeit with some minor differences dictated
+by the general constraints of Boost.MultiIndex.
+
+Ordered indices are classified into unique, which prohibit two +elements to have the same key value, and non-unique indices, +which allow for duplicates. Consider again the definition +
+ ++ ++typedef multi_index_container< + employee, + indexed_by< + ordered_unique<identity<employee> >, + ordered_non_unique<member<employee,std::string,&employee::name> > + > +> employee_set; +
+In this instantiation of multi_index_container
, the first index is to be
+treated as unique (since IDs are exclusive to each employee) and thus is declared using
+ordered_unique
, whereas the second index is non-unique (as the possibility exists
+that say two John Smiths are hired in the same company), which is specified by the use
+of ordered_non_unique
.
+
+The classification of ordered indices in unique and non-unique has an impact on which
+elements are allowed to be inserted into a given multi_index_container
; briefly put,
+unique ordered indices mimic the behavior of std::set
s while non-unique
+ordered indices are similar to std::multiset
s. For instance, an
+employee_set
can hold the objects employee(0,"George Brown")
+and employee(1,"George Brown")
, but will not accept the insertion of an
+employee
object whose ID coincides with that of some previously inserted
+employee.
+
+More than one unique index can be specified. For instance, if we augment
+employee
to include an additional member for the Social Security number,
+which is reasonably treated as unique, the following captures this design:
+
+ ++struct employee +{ + int id; + std::string name; + int ssnumber; + + employee(int id,std::string name,int ssnumber): + id(id),name(name),ssnumber(ssnumber){} + + bool operator<(const employee& e)const{return id<e.id;} +}; + +typedef multi_index_container< + employee, + indexed_by< + // sort by employee::operator< + ordered_unique<identity<employee> >, + + // sort by less<string> on name + ordered_non_unique<member<employee,std::string,&employee::name> >, + + // sort by less<int> on ssnumber + ordered_unique<member<employee,int,&employee::ssnumber> > + > +> employee_set; +
+Ordered index specifiers in indexed_by
must conform to one of the
+following syntaxes:
+
+ ++(ordered_unique | ordered_non_unique) + <[(tag)[,(key extractor)[,(comparison predicate)]]]> + +(ordered_unique | ordered_non_unique) + <[(key extractor)[,(comparison predicate)]]> +
+The first optional argument is used if tags are associated +with the index. We now proceed to briefly discuss the remaining arguments +of an ordered index specifier. +
+ +
+The first template parameter (or the second, if tags are supplied)
+in the specification of an ordered index provides a key extraction predicate.
+This predicate takes a whole element (in our example, a reference to an
+employee
object) and returns the piece of information by which
+the sorting is performed. In most cases, one of the following two situations arises:
+
employee_set
. The predefined
+identity
predicate
+can be used here as a key extractor; identity
returns as the key the
+same object passed as argument.member
, which returns
+as the key a member of the element specified by a given pointer.employee_set
. The
+definition of the first index:
+
+
++ ++ordered_unique<identity<employee> > +
+specifies by means of identity
that element
+objects themselves serve as key for this index. On the other hand, in the second
+index:
+
+ ++ordered_non_unique<member<employee,std::string,&employee::name> > +
+we use member
to extract the name
part of the
+employee
object. The key type of this index is then
+std::string
.
+
+Another common situation arises when the sorting is performed on the result
+of a particular member function. This resembles the notion of
+calculated indices supported by some relational databases.
+In these cases, the key is not a data member of the element, but rather it is
+a value returned by a particular member function. Boost.MultiIndex supports this
+kind of key extraction through
+const_mem_fun
.
+Consider the following extension of our example where sorting on the third index
+is based upon the length of the name field:
+
+ ++struct employee +{ + int id; + std::string name; + + employee(int id,std::string name,int ssnumber):id(id),name(name){} + + bool operator<(const employee& e)const{return id<e.id;} + + // returns the length of the name field + std::size_t name_length()const{return name.size();} +}; + +typedef multi_index_container< + employee, + indexed_by< + // sort by employee::operator< + ordered_unique<identity<employee> >, + + // sort by less<string> on name + ordered_non_unique<member<employee,std::string,&employee::name> >, + + // sort by less<int> on name_length() + ordered_non_unique< + const_mem_fun<employee,std::size_t,&employee::name_length> + > + > +> employee_set; +
Example 2 in the examples section
+provides a complete program showing how to use const_mem_fun
.
+Almost always you will want to use a const
member function,
+since elements in a multi_index_container
are treated as constant, much
+as elements of an std::set
. However, a
+mem_fun
+counterpart is provided for use with non-constant member functions, whose
+applicability is discussed on the paragraph on
+advanced features
+of Boost.MultiIndex key extractors in the advanced topics section.
+
+ +
+identity
, member
and const_mem_fun
serve
+most common situations in the design of a multi_index_container
. However, the
+user is free to provide her own key extractors in more exotic situations, as long as
+these conform to the Key
+Extractor
concept. For instance,
+example 6 implements several key
+extraction techniques called for when elements and/or keys are accessed via
+pointers.
+
+The last part of the specification of an ordered index is the associated
+comparison predicate, which must order the keys in a less-than fashion.
+These comparison predicates are not different from those used by STL containers like
+std::set
. By default (i.e. if no comparison predicate is provided),
+an index with keys of type key_type
sorts the elements by
+std::less<key_type>
. Should other comparison criteria be needed,
+they can be specified as an additional parameter in the index declaration:
+
+ ++// define a multiply indexed set with indices by id and by name +// in reverse alphabetical order +typedef multi_index_container< + employee, + indexed_by< + ordered_unique<identity<employee> >, // as usual + ordered_non_unique< + member<employee,std::string,&employee::name>, + std::greater<std::string> // default would be std::less<std::string> + > + > +> employee_set; +
+A given ordered index allows for lookup based on its key type, rather than the
+whole element. For instance, to find Veronica Cruz in an
+employee_set
one would write:
+
+ ++employee_set es; +... +typedef employee_set::index<name>::type employee_set_by_name; +employee_set_by_name::iterator it=es.get<name>().find("Veronica Cruz"); +
As a plus, Boost.MultiIndex provides lookup operations accepting search keys
+different from the key_type
of the index, which is a specially useful
+facility when key_type
objects are expensive to create. Ordered STL containers
+fail to provide this functionality, which often leads to inelegant workarounds: consider for
+instance the problem of determining the employees whose IDs fall in the range [0,100]. Given
+that the key of employee_set
index #0
+is employee
itself, on a first approach one would write the following:
+
+ ++employee_set::iterator p0=es.lower_bound(employee(0,"")); +employee_set::iterator p1=es.upper_bound(employee(100,"")); +
+Note however that std::less<employee>
actually only depends
+on the IDs of the employees, so it would be more convenient to avoid
+the creation of entire employee
objects just for the sake of
+their IDs. Boost.MultiIndex allows for this: define an appropriate
+comparison predicate
+
+ ++struct comp_id +{ + // compare an ID and an employee + bool operator()(int x,const employee& e2)const{return x<e2.id;} + + // compare an employee and an ID + bool operator()(const employee& e1,int x)const{return e1.id<x;} +}; +
and now write the search as
+ ++ ++employee_set::iterator p0=es.lower_bound(0,comp_id()); +employee_set::iterator p1=es.upper_bound(100,comp_id()); +
+Here we are not only passing IDs instead of employee
objects:
+an alternative comparison predicate is passed as well. In general, lookup operations
+of ordered indices are overloaded to accept
+compatible sorting
+criteria. The somewhat cumbersone definition of compatibility in this context
+is given in the reference, but roughly speaking we say that a comparison predicate
+C1
is compatible with C2
if any sequence sorted by
+C2
is also sorted with respect to C1
.
+The following shows a more interesting use of compatible predicates:
+
+ ++// sorting by name's initial +struct comp_initial +{ + bool operator()(char ch,const std::string& s)const{ + if(s.empty())return false; + return ch<s[0]; + } + + bool operator()(const std::string& s,char ch)const{ + if(s.empty())return true; + return s[0]<ch; + } +}; + +// obtain first employee whose name begins with 'J' (ordered by name) +typedef employee_set::index<name>::type employee_set_by_name; +employee_set_by_name& name_index=es.get<name>(); +employee_set_by_name::const_iterator it= + name_index.lower_bound('J',comp_initial()); +
+Range searching, i.e. the lookup of all elements in a given interval, is a very
+frequent operation for which standard lower_bound
and
+upper_bound
can be resorted to, though in a cumbersome manner.
+For instance, the following code retrieves the elements of an
+multi_index_container<double>
in the interval [100,200]:
+
+ ++typedef multi_index_container<double> double_set; +// note: default template parameters resolve to +// multi_index_container<double,indexed_by<unique<identity<double> > > >. + +typedef double_set s; +... +double_set::iterator it0=s.lower_bound(100.0); +double_set::iterator it1=s.upper_bound(200.0); +// range [it0,it1) contains the elements in [100,200] +
+Subtle changes to the code are required when strict inequalities are considered. +To retrieve the elements greater than 100 and less than 200, the +code has to be rewritten as +
+ ++ ++double_set::iterator it0=s.upper_bound(100.0); +double_set::iterator it1=s.lower_bound(200.0); +// range [it0,it1) contains the elements in (100,200) +
+To add to this complexity, the careful programmer has to take into account
+that the lower and upper bounds of the interval searched be compatible: for
+instance, if the lower bound is 200 and the upper bound is 100, the iterators
+it0
and it1
produced by the code above will be in reverse
+order, with possibly catastrophic results if a traversal from it0
+to it1
is tried. All these details make range searching a tedious
+and error prone task.
+
+The range
+member function, often in combination with
+Boost.Lambda expressions, can
+greatly help alleviate this situation:
+
+ ++using namespace boost::lambda; + +typedef multi_index_container<double> double_set; +typedef double_set s; +... +std::pair<double_set::iterator,double_set::iterator> p= + s.range(100.0<=_1,_1<=200); // 100<= x <=200 +... +p=s.range(100.0<_1,_1<200); // 100< x < 200 +... +p=s.range(100.0<=_1,_1<200); // 100<= x < 200 +
+range
simply accepts predicates specifying the lower and upper bounds
+of the interval searched. Please consult the reference for a detailed explanation
+of the permissible predicates passed to range
.
+One or both bounds can be omitted with the special unbounded
marker:
+
+ ++p=s.range(100.0<=_1,unbounded); // 100 <= x +p=s.range(unbounded,_1<200.0); // x < 200 +p=s.range(unbounded,unbounded); // equiv. to std::make_pair(s.begin(),s.end()) +
+The replace
member function
+performs in-place replacement of a given element as the following example shows:
+
+ ++typedef index<employee_set,name>::type employee_set_by_name; +employee_set_by_name& name_index=es.get<name>(); + +employee_set_by_name::iterator it=name_index.find("Anna Jones"); +employee anna=*it; +anna.name="Anna Smith"; // she just got married to Calvin Smith +name_index.replace(it,anna); // update her record +
+replace
performs this substitution in such a manner that:
+
multi_index_container
+remains unchanged if some exception (originated by the system or the user's data
+types) is thrown.
+replace
is a powerful operation not provided by standard STL
+containers, and one that is specially handy when strong exception-safety is
+required.
+
+
+
+The observant reader might have noticed that the convenience of replace
+comes at a cost: namely the whole element has to be copied twice to do
+the updating (when retrieving it and inside replace
). If elements
+are expensive to copy, this may be quite a computational cost for the modification
+of just a tiny part of the object. To cope with this situation, Boost.MultiIndex
+provides an alternative updating mechanism called
+modify
:
+
+ ++struct change_name +{ + change_name(const std::string& new_name):new_name(new_name){} + + void operator()(employee& e) + { + e.name=new_name; + } + +private: + std::string new_name; +}; +... +typedef employee_set::index<name>::type employee_set_by_name; +employee_set_by_name& name_index=es.get<name>(); + +employee_set_by_name::iterator it=name_index.find("Anna Jones"); +name_index.modify(it,change_name("Anna Smith")); +
modify
accepts a functor (or pointer to function) that is
+passed a reference to the element to be changed, thus eliminating the need
+for spurious copies. Like replace
, modify
does preserve
+the internal orderings of all the indices of the multi_index_container
.
+However, the semantics of modify
is not entirely equivalent to
+replace
. Consider what happens if a collision occurs as a result
+of modifying the element, i.e. the modified element clashes with another with
+respect to some unique ordered index. In the case of replace
, the
+original value is kept and the method returns without altering the container, but
+modify
cannot afford such an approach, since the modifying functor
+leaves no trace of the previous value of the element. Integrity constraints
+thus lead to the following policy: when a collision happens in the
+process of calling modify
, the element is erased and the method returns
+false
. This difference in behavior between replace
and
+modify
has to be considered by the programmer on a case-by-case basis.
+
+A key-based version of modify
, named
+modify_key
, is
+provided as well. In this case, the modifying functor is passed a reference to
+the key_value
part of the element instead of the whole object. Note
+that modify_key
cannot be used for key extractors which return calculated
+values instead of references to data members of the elements, such
+as const_mem_fun
.
+
+ ++struct change_str +{ + change_str(const std::string& new_str):new_str(new_str){} + + // note this is passed a string, not an employee + void operator()(std::string& str) + { + str=new_str; + } + +private: + std::string new_str; +}; +... +typedef employee_set::index<name>::type employee_set_by_name; +employee_set_by_name& name_index=es.get<name>(); + +employee_set_by_name::iterator it=name_index.find("Anna Jones"); +name_index.modify_key(it,change_str("Anna Smith")); +
+Just as modify
does, modify_key
erases the element if
+the modification results in collisions in some index. modify
and
+modify_key
are particularly well suited to use in conjunction to
+Boost.Lambda
+for defining the modifying functors:
+
+ ++using namespace boost::lambda; + +typedef employee_set::index<name>::type employee_set_by_name; +employee_set_by_name& name_index=es.get<name>(); + +employee_set_by_name::iterator it=name_index.find("Anna Jones"); +name_index.modify_key(it,_1="Anna Smith"); +
+Unlike ordered indices, sequenced indices do not impose a fixed order on the
+elements: instead, these can be arranged in any position on the sequence, in the
+same way as std::list
permits. The interface of sequenced indices
+is thus designed upon that of std::list
; nearly every operation
+provided in the standard container is replicated here, occasionally with changes
+in the syntax and/or semantics to cope with the constraints imposed by
+Boost.MultiIndex. In particular, there is an important limitation of sequenced
+indices with respect to std::list
s, namely that elements of an
+multi_index_container
are not mutable through an iterator:
+
+ ++multi_index_container< + int, + indexed_by<sequenced<> > +> s; // list-like container + +s.push_front(0); +*(s.begin())==1; // ERROR: the element cannot be changed +
+That is, iterators of a sequenced index (of all types of indices, actually)
+point to constant elements. This limitation might come as a surprise, but
+it is imposed by the way multi_index_container
s work; if elements were
+allowed to be changed in this manner, we could introduce inconsistencies
+in other ordered indices of the multi_index_container
. Element modification
+can nevertheless be done by means of
+update operations.
+
+Consider a multi_index_container
with two or more indices, one of them
+of sequenced type. If an element is inserted through another index,
+then it will be automatically appended to the end of the sequenced index.
+An example will help to clarify this:
+
+ ++multi_index_container< + int, + indexed_by< + sequenced<>, // sequenced type + ordered_unique<identity<int> > // another index + > +> s; + +s.get<1>().insert(1); // insert 1 through index #1 +s.get<1>().insert(0); // insert 0 through index #1 + +// list elements through sequenced index #0 +std::copy(s.begin(),s.end(),std::ostream_iterator<int>(std::cout)); + +// result: 1 0 +
+Thus the behavior of sequenced indices when insertions are not made through +them is to preserve insertion order. +
+ +
+Sequenced indices are specified with the sequenced
construct:
+
+ ++sequenced<[(tag)]> +
+The tag parameter is optional. +
+ +
+As mentioned before, sequenced indices mimic the interface of
+std::list
, and most of the original operations therein are
+provided as well. The semantics and complexity of these operations, however,
+do not always coincide with those of the standard container. Differences
+result mainly from the fact that insertions into a sequenced index are not
+guaranteed to succeed, due to the possible banning by other indices
+of the multi_index_container
. Consult the
+reference for further details.
+
+Like ordered indices, sequenced indices provide
+replace
and
+modify
+operations, with identical functionality. There is however no analogous
+modify_key
, since sequenced indices are not key-based.
+
+Given indices i1
and i2
on the same multi_index_container
,
+project
can be used to
+retrieve an i2
-iterator from an i1
-iterator, both of them
+pointing to the same element of the set. This functionality allows the programmer to
+move between different indices of the same multi_index_container
when performing
+elaborate operations:
+
+ ++typedef employee_set::index<name>::type employee_set_by_name; +employee_set_by_name& name_index=es.get<name>(); + +// list employees by ID starting from Robert Brown's ID + +employee_set_by_name::iterator it1=name_index.find("Robert Brown"); + +// obtain an iterator of index #0 from it1 +employee_set::iterator it2=es.project<0>(it1); + +std::copy(it2,es.end(),std::ostream_iterator<employee>(std::cout)); +
+A slightly more interesting example: +
+ ++ ++text_container tc; + +// get a view to index #1 (ordered index on the words) +text_container::nth_index<1>::type& sorted_index=tc.get<1>(); + +// prepend "older" to all occurrences of "sister" + +text_container::nth_index_iterator<1>::type it1= + sorted_index.lower_bound("sister"); + +while(it1!=sorted_index.end()&&*it1=="sister"){ + // convert to an iterator to the sequenced index + text_container::iterator it2=tc.project<0>(it1); + + tc.insert(it2,"older"); + ++it1; +} +
+When provided, project
can also be used with
+tags.
+
+multi_index_container
provides the same complexity and exception safety
+guarantees as the equivalent STL containers do. Iterator and reference validity
+is preserved in the face of insertions, even for replace and modify operations.
+
+Appropriate instantiations of multi_index_container
can in fact simulate
+std::set
, std::multiset
and (with more limitations)
+std::list
, as shown in the
+advanced topics
+section. These simulations are as nearly as efficient as the original STL
+containers; consult the reference for further
+information on complexity guarantees and the
+performance section for practical measurements of
+efficiency.
+
Revised May 7th 2004
+ +Copyright © 2003-2004 Joaquín M López Muñoz. +Use, modification, and distribution are subject to the Boost Software +License, Version 1.0. (See accompanying file +LICENSE_1_0.txt or copy at +www.boost.org/LICENSE_1_0.txt) +
+ + + diff --git a/doc/up.gif b/doc/up.gif new file mode 100644 index 0000000..acb3777 Binary files /dev/null and b/doc/up.gif differ diff --git a/example/Jamfile b/example/Jamfile new file mode 100644 index 0000000..c036f5e --- /dev/null +++ b/example/Jamfile @@ -0,0 +1,44 @@ +# Boost.MultiIndex examples Jamfile +# +# Copyright Joaquín M López Muñoz 2003-2004. Use, modification, and distribution +# are subject to 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. + +subproject libs/multi_index/example ; + +exe basic + : basic.cpp + :