commit b35bef74e475a3735d105d440bd0f5f6f2382c42 Author: Joaquín M. López Muñoz Date: Fri May 7 10:44:23 2004 +0000 initial commit [SVN r22759] diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..3e84d7c --- /dev/null +++ b/.gitattributes @@ -0,0 +1,96 @@ +* text=auto !eol svneol=native#text/plain +*.gitattributes text svneol=native#text/plain + +# Scriptish formats +*.bat text svneol=native#text/plain +*.bsh text svneol=native#text/x-beanshell +*.cgi text svneol=native#text/plain +*.cmd text svneol=native#text/plain +*.js text svneol=native#text/javascript +*.php text svneol=native#text/x-php +*.pl text svneol=native#text/x-perl +*.pm text svneol=native#text/x-perl +*.py text svneol=native#text/x-python +*.sh eol=lf svneol=LF#text/x-sh +configure eol=lf svneol=LF#text/x-sh + +# Image formats +*.bmp binary svneol=unset#image/bmp +*.gif binary svneol=unset#image/gif +*.ico binary svneol=unset#image/ico +*.jpeg binary svneol=unset#image/jpeg +*.jpg binary svneol=unset#image/jpeg +*.png binary svneol=unset#image/png +*.tif binary svneol=unset#image/tiff +*.tiff binary svneol=unset#image/tiff +*.svg text svneol=native#image/svg%2Bxml + +# Data formats +*.pdf binary svneol=unset#application/pdf +*.avi binary svneol=unset#video/avi +*.doc binary svneol=unset#application/msword +*.dsp text svneol=crlf#text/plain +*.dsw text svneol=crlf#text/plain +*.eps binary svneol=unset#application/postscript +*.gz binary svneol=unset#application/gzip +*.mov binary svneol=unset#video/quicktime +*.mp3 binary svneol=unset#audio/mpeg +*.ppt binary svneol=unset#application/vnd.ms-powerpoint +*.ps binary svneol=unset#application/postscript +*.psd binary svneol=unset#application/photoshop +*.rdf binary svneol=unset#text/rdf +*.rss text svneol=unset#text/xml +*.rtf binary svneol=unset#text/rtf +*.sln text svneol=native#text/plain +*.swf binary svneol=unset#application/x-shockwave-flash +*.tgz binary svneol=unset#application/gzip +*.vcproj text svneol=native#text/xml +*.vcxproj text svneol=native#text/xml +*.vsprops text svneol=native#text/xml +*.wav binary svneol=unset#audio/wav +*.xls binary svneol=unset#application/vnd.ms-excel +*.zip binary svneol=unset#application/zip + +# Text formats +.htaccess text svneol=native#text/plain +*.bbk text svneol=native#text/xml +*.cmake text svneol=native#text/plain +*.css text svneol=native#text/css +*.dtd text svneol=native#text/xml +*.htm text svneol=native#text/html +*.html text svneol=native#text/html +*.ini text svneol=native#text/plain +*.log text svneol=native#text/plain +*.mak text svneol=native#text/plain +*.qbk text svneol=native#text/plain +*.rst text svneol=native#text/plain +*.sql text svneol=native#text/x-sql +*.txt text svneol=native#text/plain +*.xhtml text svneol=native#text/xhtml%2Bxml +*.xml text svneol=native#text/xml +*.xsd text svneol=native#text/xml +*.xsl text svneol=native#text/xml +*.xslt text svneol=native#text/xml +*.xul text svneol=native#text/xul +*.yml text svneol=native#text/plain +boost-no-inspect text svneol=native#text/plain +CHANGES text svneol=native#text/plain +COPYING text svneol=native#text/plain +INSTALL text svneol=native#text/plain +Jamfile text svneol=native#text/plain +Jamroot text svneol=native#text/plain +Jamfile.v2 text svneol=native#text/plain +Jamrules text svneol=native#text/plain +Makefile* text svneol=native#text/plain +README text svneol=native#text/plain +TODO text svneol=native#text/plain + +# Code formats +*.c text svneol=native#text/plain +*.cpp text svneol=native#text/plain +*.h text svneol=native#text/plain +*.hpp text svneol=native#text/plain +*.ipp text svneol=native#text/plain +*.tpp text svneol=native#text/plain +*.jam text svneol=native#text/plain +*.java text svneol=native#text/plain diff --git a/Jamfile b/Jamfile new file mode 100644 index 0000000..b7f7391 --- /dev/null +++ b/Jamfile @@ -0,0 +1,16 @@ +# Boost.MultiIndex examples and tests 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 ; + +# please order by name to ease maintenance + +subinclude libs/multi_index/example ; +subinclude libs/multi_index/test ; +subinclude libs/multi_index/perf ; diff --git a/doc/acknowledgements.html b/doc/acknowledgements.html new file mode 100644 index 0000000..df57256 --- /dev/null +++ b/doc/acknowledgements.html @@ -0,0 +1,124 @@ + + + + + +Boost.MultiIndex Documentation - Acknowledgements + + + + +

c++boost.gif (8819 bytes)Boost.MultiIndex Acknowledgements

+ + + +
+ +
+ +

+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: +

+ +
+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. +
+

+ +
+ + + +
+ +
+ +

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/advanced_topics.html b/doc/advanced_topics.html new file mode 100644 index 0000000..9435649 --- /dev/null +++ b/doc/advanced_topics.html @@ -0,0 +1,1321 @@ + + + + + +Boost.MultiIndex Documentation - Advanced topics + + + + +

c++boost.gif (8819 bytes)Boost.MultiIndex Advanced topics

+ + + +
+ +
+ +

Contents

+ + + +

Composite keys

+ +

+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_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;
+
+ +

+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: +

+ +
+phonebook pb;
+...
+// look for all Whites
+std::pair<phonebook::iterator,phonebook::iterator> p=
+  pb.equal_range(boost::make_tuple(std::string("White")));
+
+ +

+On the other hand, partial searches without specifying the first keys are not +allowed. +

+ +

+By default, the corresponding 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;
+
+ +

+See Example 7 in the examples section +for an application of composite_key. +

+ +

Advanced features of Boost.MultiIndex key +extractors

+ +

+The 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;}
+};
+
+ +

+This possibility is fully exploited by predefined key extractors provided +by Boost.MultiIndex, making it simpler to define multi_index_containers +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;
+
+ +

+Note that this is specified in exactly the same manner as a 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;
+
+ +

+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 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 multi_index_containers from preexisting +multi_index_containers. +

+ +

+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. +

+ +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Use cases for Boost.MultiIndex key extractors.
element typesorted bykey extractorapplicable to
const elements?
read/write?
Timember<T,int,&T::i>yesyes
jmember<T,const int,&T::j>yesno
f()const_mem_fun<T,int,&T::f>yesno
g()mem_fun<T,int,&T::g>nono
reference_wrapper<T>imember<T,int,&T::i>yesyes
jmember<T,const int,&T::j>yesno
f()const_mem_fun<T,int,&T::f>yesno
g()mem_fun<T,int,&T::g>yesno
reference_wrapper<const T>imember<T,const int,&T::i>yesno
jmember<T,const int,&T::j>yesno
f()const_mem_fun<T,int,&T::f>yesno
g() 
chained pointer to T
+ or to reference_wrapper<T>
imember<T,int,&T::i>yesyes
jmember<T,const int,&T::j>yesno
f()const_mem_fun<T,int,&T::f>yesno
g()mem_fun<T,int,&T::g>yesno
chained pointer to const T
+ or to reference_wrapper<const T>
imember<T,const int,&T::i>yesno
jmember<T,const int,&T::j>yesno
f()const_mem_fun<T,int,&T::f>yesno
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_containers +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. +

+ +

Use of 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: +

+In these cases, a replacement utility +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 +

+If you detect this defect in a compiler other than these, you can take +advantage of BOOST_MULTI_INDEX_MEMBER by manually defining +BOOST_NO_POINTER_TO_MEMBER_TEMPLATE_PARAMETERS prior to the +inclusion of Boost.MultiIndex headers. +

+ +

Use of 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_results: +

+ +
+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. +

+ +

Use of ctor_args_list

+ +

+Although in most cases multi_index_containers 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. +

+ +

Debugging support

+ +

+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: +

+These two modes are independent of each other and can be set on or off +individually. It is important to note that errors detected by safe mode are +due in principle to faulty code in the user's program, while +invariant-checking mode detects potential internal bugs in the +implementation of Boost.MultiIndex. +

+ +

Safe mode

+ +

+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. +

+ +

Invariant-checking mode

+ +

+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. +

+ +

Simulating standard containers with + multi_index_container

+ +

Simulation of associative +containers

+ +

+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::multisets 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::multisets, but rather a +std::pair<iterator,bool> in the spirit of std::sets. +In this particular case, however, the bool member of the returned +pair is always true. +

+ +

+The case of std::maps and std::multimaps 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::maps and +std::multimaps. 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. +

+ +

Simulation of 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<> > >
+
+ +

Metaprogramming and 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. +

+ +

MPL analysis

+ +

+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: +

+Each of these types is a +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. +

+ +

MPL synthesis

+ +

+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 Documentation - Compiler specifics + + + + +

c++boost.gif (8819 bytes)Boost.MultiIndex Compiler specifics

+ + + +
+ +
+ +

+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. +

+ +

Contents

+ + + +

Borland C++ Builder 6.4

+ +

+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. +

+ +

GNU GCC 3.3.1 (cygming special)

+ +

+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. +

+ +

Intel C++ Compiler for Windows 32-bit 7.0/7.1

+ +

+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. +

+ +

Intel C++ Compiler for Windows 32-bit 8.0

+ +

+No problems have been detected with this compiler. +

+ +

Metrowerks CodeWarrior 9.2 for Mac OS

+ +

+No problems have been detected with this compiler. +

+ + +

Microsoft Visual C++ 6.0 Service Pack 5

+ +

+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: +

+You can use instead their global equivalents. Also, this compiler does not +implement Koenig lookup, so you might need to explicitly qualify these +global names with ::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 +

+This operation results in a modest reduction of the lengths of symbol +names. +

+ +
+ +

+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: +

+

+ +

+Microsoft Visual C++ 6.0 Service Pack 5 ++ STLport 4.6.2 +

+ +

+Boost.MultiIndex works for this configuration. The same limitations apply as +in MSVC++ 6.0 with its original Dinkumware standard library. +

+ +

Microsoft Visual C++ 7.1

+ +

+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 @@ + + + + + +Boost.MultiIndex Documentation - Examples + + + + +

c++boost.gif (8819 bytes)Boost.MultiIndex Examples

+ + + +
+ +
+ +

Contents

+ + + +

Example 1: basic usage

+ +

+See source code. +

+ +

+Basic program showing the multi-indexing capabilities of Boost.MultiIndex +with an admittedly boring set of employee records. +

+ +

Example 2: using member functions as keys

+ +

+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. +

+ +

Example 3: constructing multi_index_containers +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. +

+ +

Example 4: bidirectional map

+ +

+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. +

+ +

Example 5: sequenced indices

+ +

+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. +

+ +

Example 6: complex searches and foreign keys

+ +

+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: +

    +
  1. Select the elements with the given manufacturer by means + of equal_range, +
  2. feed these elements into a multi_index_container sorted + by price, +
  3. select by price using lower_bound and + upper_bound; +
+or alternatively: +
    +
  1. Select the elements within the price range with + lower_bound and upper_bound, +
  2. feed these elements into a multi_index_container sorted + by manufacturer, +
  3. locate the elements with given manufacturer using + equal_range. +
+An interesting technique developed in the example lies in +the construction of the intermediate multi_index_container. +In order to avoid object copying, appropriate view types +are defined with multi_index_containers having as elements +pointers to car_models instead of actual objects. +These views have to be supplemented with appropriate +dereferencing key extractors. +

+ +

Example 7: composite keys

+ +

+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: +

+The reason that the order is made firstly by the directory in which +the files are located obeys to the local nature of the shell commands, +like for instance ls. The shell simulation only has three +commands: + +The program exits when the user presses the Enter key at the command prompt. +

+ +

+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 @@ + + + + + +Boost.MultiIndex Documentation - Future work + + + + +

c++boost.gif (8819 bytes)Boost.MultiIndex Future work

+ + + +
+ +
+ +

+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. +

+ +

Contents

+ + + +

Hashed indices

+ +

+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. +

+ +

Ranked indices

+ +

+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

+ +

+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: +

    +
  1. Logging,
  2. +
  3. interfacing to GUI-based applications,
  4. +
  5. synchronization between separate data structures.
  6. +
+

+ +

+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
+
+ +

Constraints

+ +

+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;
+
+ +

User-defined indices

+ +

+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. +

+ +

Bidirectional map

+ +

+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. +

+ +

Indexed maps

+ +

+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. +

+ +

Serialization support

+ +

+Once Robert Ramey's +serialization library gets accepted into Boost, support for +archiving/retrieving multi_index_containers should be added. +

+ +

Move semantics

+ +

+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_containers 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_containers. 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 @@ + + + + + +Boost.MultiIndex Documentation - Index + + + + +

c++boost.gif (8819 bytes)Boost Multi-index Containers Library

+ + + +
+ +
+ +

+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. +

+ +

Contents

+ + + +
+ + + +
+ +
+ +

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 @@ + + + + + +Boost.MultiIndex Documentation - Performance + + + + +

c++boost.gif (8819 bytes)Boost.MultiIndex Performance

+ + + +
+ +
+ +

Contents

+ + + +

Introduction

+ +

+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_containers with two or more indices, the running time +can be reduced to half as long as with manual simulations involving several +STL containers. +

+ +

Manual simulation of a multi_index_container

+ +

+The section of simulation +of standard containers with multi_index_container shows the equivalence +between single-index multi_index_containers 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: +

+ +
+manual_t1 c1;
+manual_t2 c2;
+
+// insert the element 5
+manual_t1::iterator=c1.insert(5).first;
+c2.insert(&*t1);
+
+ +deletion, on the other hand, necessitates a logarithmic search, whereas +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. +

+ +

Spatial efficiency

+ +

+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. +

+ +

Time efficiency

+ +

+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_containers with two or more indices. +

+ +

In the special case of multi_index_containers 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. +

+ +

Performance tests

+ +

+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: +

+with their default release settings. All tests were performed on a Wintel +box equipped with a P4 1.5GHz processor and 256 MB RAM, running +Microsoft Windows 2000 Professional SP2. +

+ +

+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. +

+ +

Results for 1 ordered index

+ +

+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>. +

+ +

Memory consumption

+ +

+ + + + + + + + + + + +
GCC 3.1.1ICC 7.1MSVC 6.5
100%100%100%
+Table 1: Relative memory consumption of 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. +

+ +

Execution time

+ +

+performance of multi_index_container with 1 ordered index
+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. +

+ +

Results for 1 sequenced index

+ +

+The following instantiation of multi_index_container was tested: +

+ +
+multi_index_container<
+  int,
+  indexed_by<
+    sequenced<>
+  >
+>
+
+ +

+which is functionally equivalent to std::list<int>. +

+ +

Memory consumption

+ +

+ + + + + + + + + + + +
GCC 3.1.1ICC 7.1MSVC 6.5
100%100%100%
+Table 2: Relative memory consumption of 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. +

+ +

Execution time

+ +

+performance of multi_index_container with 1 sequenced index
+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%. +

+ +

Results for 2 ordered indices

+ +

+The following instantiation of multi_index_container was tested: +

+ +
+multi_index_container<
+  int,
+  indexed_by<
+    ordered_unique<identity<int> >,
+    ordered_non_unique<identity<int> >
+  >
+>
+
+ +

Memory consumption

+ +

+ + + + + + + + + + + +
GCC 3.1.1ICC 7.1MSVC 6.5
90%90%90%
+Table 3: Relative memory consumption of multi_index_container with 2 +ordered indices. +

+ +

+These results concinde with the theoretical formula for +SI=36 and p=4. +

+ +

Execution time

+ +

+performance of multi_index_container with 2 ordered indices
+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. +

+ +

Results for 1 ordered index + 1 sequenced index

+ +

+The following instantiation of multi_index_container was tested: +

+ +
+multi_index_container<
+  int,
+  indexed_by<
+    ordered_unique<identity<int> >,
+    sequenced<>
+  >
+>
+
+ +

Memory consumption

+ +

+ + + + + + + + + + + +
GCC 3.1.1ICC 7.1MSVC 6.5
87.5%87.5%87.5%
+Table 4: Relative memory consumption of multi_index_container with 1 +ordered index + 1 sequenced index. +

+ +

+These results concinde with the theoretical formula for +SI=28 and p=4. +

+ +

Execution time

+ +

+
+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.) +

+ +

Results for 3 ordered indices

+ +

+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> >
+  >
+>
+
+ +

Memory consumption

+ +

+ + + + + + + + + + + +
GCC 3.1.1ICC 7.1MSVC 6.5
86.7%86.7%86.7%
+Table 5: Relative memory consumption of multi_index_container with 3 +ordered indices. +

+ +

+These results concinde with the theoretical formula for +SI=52 and p=4. + +

+ +

Execution time

+ +

+performance of multi_index_container with 3 ordered indices
+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. +

+ +

Results for 2 ordered indices + 1 sequenced index

+ +

+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<>
+  >
+>
+
+ +

Memory consumption

+ +

+ + + + + + + + + + + +
GCC 3.1.1ICC 7.1MSVC 6.5
84.6%84.6%84.6%
+Table 6: Relative memory consumption of multi_index_container with 2 +ordered indices + 1 sequenced index. +

+ +

+These results concinde with the theoretical formula for +SI=44 and p=4. +

+ +

Execution time

+ +

+
+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%. +

+ +

Conclusions

+ +

+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_containers, 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 @@ + + + + + +Boost.MultiIndex Documentation - Reference + + + + +

c++boost.gif (8819 bytes)Boost.MultiIndex Reference

+ + + +
+ +
+ +

Contents

+ + + +

Header dependencies

+ +

+The following dependencies among headers of Boost.MultiIndex hold: +

+So, a program using Boost.MultiIndex must include + +"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.MultiIndex Documentation - Index reference + + + + +

c++boost.gif (8819 bytes)Boost.MultiIndex Index reference

+ + + +
+ +
+ +

Contents

+ + + +

Index concepts

+ +

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

+ +

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

+ +

+Insertion and erasing of elements are always performed through the +appropriate interface of some index of the multi_index_container; +these operations, however, do have an impact on all other indices as +well: for instance, insertion through a given index may fail because +there exists another index which bans the operation in order to preserve +its invariant (like uniqueness of elements.) This circumstance, rather +than 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: +

+The last two primitives deserve some further explanation: in order to +guarantee the invariants associated to each index (e.g. some definite +ordering,) elements of a multi_index_container are not mutable. +To overcome this restriction, indices expose member functions +for 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.) +

+ +

Complexity signature

+ +

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

+ +

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

+ +

+Each function yields the complexity estimate of the contribution of the index +to the corresponding global primitive. Let us consider +an instantiation of multi_index_container +with N indices labelled 0,...,N-1 +whose complexity signatures are +(ci,ii,hi,di,ri,mi); +the insertion of an element in such a 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: + +For instance, consider a multi_index_container with two ordered indices, +for which i(n)=log(n), and a sequenced index with i(n)=1 +(constant time insertion). Insertion of an element into this multi_index_container +is then of complexity +
+O(I(n))=O(2*log(n)+1)=O(log(n)). +
+

+ +

Index specification

+ +

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

+ +

+Header + +"boost/multi_index/indexed_by.hpp" synopsis

+ +
+namespace boost{
+
+namespace multi_index{
+
+template<typename T0,...,typename Tn>
+struct indexed_by;
+
+} // namespace boost::multi_index 
+
+} // namespace boost
+
+ +

Template class 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

+ +

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

+ +

+Header + +"boost/multi_index/tag.hpp" synopsis

+ +
+namespace boost{
+
+namespace multi_index{
+
+template<typename T0,...,typename Tn>
+struct tag;
+
+} // namespace boost::multi_index 
+
+} // namespace boost
+
+ +

Template class 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 provided by Boost.MultiIndex

+ + +

Key-based indices

+ +

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

+

+ +

Other types

+ +

+

+

+ +
+ + + +
+ +
+ +

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.MultiIndex Documentation - Key extraction reference + + + + +

c++boost.gif (8819 bytes)Boost.MultiIndex Key extraction reference

+ + + +
+ +
+ +

Contents

+ + + +

Key Extractors

+ +

+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 +

    +
  1. the type KeyFromValue::result_type is defined,
  2. +
  3. k1(ca) is defined and returns a value convertible + to const KeyFromValue::result_type&,
  4. +
  5. if k2 is a copy of k1, k1(ca) is the + same value as k2(ca),
  6. +
+for every 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: +

    +
  1. k1(a) is defined and returns a value convertible + to KeyFromValue::result_type&,
  2. +
  3. const_cast<const KeyFromValue::result_type&>(k1(a)) + is the same value as + k1(const_cast<const Type&>(a)),
  4. +
+for every k1 of type const KeyFromValue and +a of type Type&. +

+ +

+Boost.MultiIndex provides five general-purpose key extractors: +

+plus replacements for some of them: + +that workaround some deficiencies in the support for non-type template parameters +by certain compilers. +

+ +

Chained pointers

+ +

+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 +

+that is, chained pointers are arbitrary compositions of pointer-like objects +ultimately dereferencing to values of Type& or +boost::reference_wrapper<Type>. +

+ +

Header + +"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. +

+ +

+Header + +"boost/multi_index/identity.hpp" synopsis

+ +
+namespace boost{
+
+namespace multi_index{
+
+template<typename T> struct identity;
+
+} // namespace boost::multi_index 
+
+} // namespace boost
+
+ +

Template class 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: +

+

+ +

identity members

+ +template<typename ChainedPtr> Type& operator()(const ChainedPtr& x)const; + +
+Requires: ChainedPtr is a chained pointer +type to Type.
+Returns: a reference to the object chained-pointed to by x. +
+ +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(). +
+ + +

+Header + +"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
+
+ +

Template class 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: +

+

+ +

member members

+ +template<typename ChainedPtr> Type& operator()(const ChainedPtr& x)const; + +
+Requires: ChainedPtr is a chained pointer +type to Type.
+Returns: a reference to the object chained-pointed to by x. +
+ +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. +
+ +

Template class 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: +

+In this situation, 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)>. +

+ +

Macro 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: +

+and/or if the macro BOOST_NO_POINTER_TO_MEMBER_TEMPLATE_PARAMETERS +is defined. +

+ +

+Header + +"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
+
+ +

Template class 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: +

+

+ +

const_mem_fun members

+ +template<typename ChainedPtr> Type operator()(const ChainedPtr& x)const; + +
+Requires: ChainedPtr is a chained pointer +type to Type.
+Returns: (y.*PtrToMemberFunction)(), where y is the +object chained-pointed to by x. +
+ +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)(). +
+ +

Template class 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: +

+

+ +

mem_fun members

+ +template<typename ChainedPtr> Type operator()(const ChainedPtr& x)const; + +
+Requires: ChainedPtr is a chained pointer +type to Type.
+Returns: (y.*PtrToMemberFunction)(), where y is the +object chained-pointed to by x. +
+ +Type operator()(Class& x)const; + +
+Returns: (x.*PtrToMemberFunction)(). +
+ +Type operator()(const reference_wrapper<Class>& x)const; + +
+Returns: (x.get().*PtrToMemberFunction)(). +
+ +

Template class 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>. +

+ +

Template class 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;
+};
+
+ +

Macro +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. +

+ + +

Macro +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. +

+ +

+Header + +"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
+
+ +

Template class 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: +

+

+ +

composite_key members

+ +composite_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 in x. +
+ +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 to result_type.
+Returns: a result_type object dependent on +*this and y, where y is the +object chained-pointed to by x. +
+ +result_type operator()(const value_type& x)const; + +
+Returns: a result_type object dependent on +*this and x. +
+ +result_type operator()(const reference_wrapper<const value_type>& x)const; + +
+Returns: a result_type object dependent on +*this and x.get(). +
+ +result_type operator()(const reference_wrapper<value_type>& x)const; + +
+Returns: a result_type object dependent on +*this and x.get(). +
+ +

Template class +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. +

+ +

Notation

+ +

+Given an x of type composite_key_result<CompositeKey>, +we use the following notation: +

+Also, if y is a tuple of values, we define: + +

+ +

Comparison operators

+ +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 all i +in [0,length(x)).
+Returns: true if and only if +
+xi==yi for all i +in [0,length(x)). +
+Complexity: No more key extraction operations and comparisons +are performed than those necessary for the evaluation of the expression above, +starting at i==0. The evaluation is short-circuited as soon as +the result is determined to be false. +
+ +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 all i +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 +
+!(xi<yi) && !(yi<xi) +for all i in [0,j),
+  xj<yj. +
+Complexity: No more key extraction operations and comparisons +are performed than those necessary for the evaluation of the expression above, +starting at i==0. The evaluation is short-circuited as soon as +the result is determined to be false. +
+ +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 <=). +
+
+ +

Template class +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. +

+ +

Notation

+ +

+In what follows we use the same notation +introduced for composite_key_result. + +

composite_key_compare members

+ +composite_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 in x. +
+ +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 all i +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 +
+!key_comps().get<i>()(xi,yi) && !key_comps().get<i>()(yi,xi) +for all i in [0,j),
+ key_comps().get<j>()(xj,yj). +
+Complexity: No more key extraction operations and comparisons +are performed than those necessary for the evaluation of the expression above, +starting at i==0. The evaluation is short-circuited as soon as +the result is determined to be false. +
+ +

Template class +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. +

+ +

Template class +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. +

+ +

Specialization of 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
+
+ +

Specialization of 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
+
+ +

Ordering semantics

+ +

+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 +

+KeyFromValuei::result_type = Ti, for all i = 0,...,j. +
+Then, 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>: +
+tuple<Q0,...,Qk>, k <= n
+composite_key_result<composite_key<K0,...,Kk> >, with +Ki::result_type = Qi for all i = 0,...,k. +
+provided that each 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_results 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 @@ + + + + + +Boost.MultiIndex Documentation - multi_index_container reference + + + + +

c++boost.gif (8819 bytes)Boost.MultiIndex +multi_index_container reference

+ + + +
+ +
+ +

Contents

+ + + +

+Header +"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. +

+ +

+Header +"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
+
+ +

+Template class 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
+
+ +

Complexity

+ +

+In the descriptions of operations of multi_index_container, we adopt the +scheme outlined in the +complexity signature section. +

+ +

Instantiation types

+ +

+multi_index_container is instantiated with the following types: +

    +
  1. Value is the + Assignable + type of the elements contained.
  2. +
  3. 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. +
  4. Allocator must comply with the C++ requirements for + allocators [lib.allocator.requirements]. +
+Indices of a given multi_index_container instantiation cannot have +duplicate tags, either within a single +index or in two different indices. +

+ +

Nested types

+ +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>, +where Ci is the ctor_args type of the +i-th index held by the multi_index_container, in the +same order as they were specified. Strictly speaking, there is an +implicit conversion from +const ::boost::tuple<C0,...,CI-1>& +to const 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 all ctor_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 the multi_index_container, in the same order as +they were provided. +
+ +index_type_list + +
+ +MPL Forward Sequence containing the types of the indices held by +the multi_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 the multi_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 the multi_index_container, in the same order +as they were specified. +
+ +

Nested class templates

+ +template<int N> struct nth_index + +
+nth_index<N>::type yields the type of the +N-th (0-based) index held by the multi_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 +has Tag as an associated tag type.
+Requires: Some index of the multi_index_container has Tag +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.
+
+ +

Constructors, copy and assignment

+ +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 to Value. +last is reachable from first.
+Effects: Constructs and empty multi_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 the multi_index_container.
+Complexity: O(m*H(m)), where m 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 the multi_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 from x.
+Postconditions: *this==x. The order on every index +of the multi_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 of ctor_args_list do not throw. +
+ +allocator_type get_allocator()const; + +
+Returns a copy of the allocator_type object used to construct +the multi_index_container.
+Complexity: Constant. +
+ +

Index retrieval operations

+ +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 a const 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 that index<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 that index<Tag>::type +is valid.
+Effects: Returns a const reference to the +index<Tag>::type index held by +*this.
+Complexity: Constant.
+Exception safety: nothrow. +
+ +

Projection operations

+ +

+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: +

+

+ +template<int N,typename IteratorType>
+typename nth_index_iterator<N>::type project(IteratorType it);
+ +
+Requires: 0 <= N < I. IteratorType +belongs to iterator_type_list. it is a valid +iterator of some index of *this (i.e. does not refer to some +other multi_index_container.)
+Effects: Returns an nth_index_iterator<N>::type iterator +equivalent to it.
+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 to const_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 other multi_index_container.)
+Effects: Returns an nth_index_const_iterator<N>::type +iterator equivalent to it.
+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 to iterator_type_list. it is a valid +iterator of some index of *this (i.e. does not refer to some +other multi_index_container.)
+Effects: Returns an index_iterator<Tag>::type iterator +equivalent to it.
+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 to const_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 other multi_index_container.)
+Effects: Returns an index_const_iterator<Tag>::type +iterator equivalent to it.
+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.MultiIndex Documentation - Ordered indices reference + + + + +

c++boost.gif (8819 bytes)Boost.MultiIndex Ordered indices reference

+ + + +
+ +
+ +

Contents

+ + + +

+Header + +"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. +

+ +

+Header + +"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
+
+ +

+Index specifiers 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. +

+ +

Ordered indices

+ +

+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::sets +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
+
+ +

Complexity signature

+ +

+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: +

+

+ +

Instantiation types

+ +

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: +

+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. +

+ +

Constructors, copy and assignment

+ +

+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: +
+a=b;
+
+where a and b are the multi_index_container +objects to which *this and x belongs, respectively.
+Returns: *this.
+
+ +

Modifiers

+ +std::pair<iterator,bool> insert(const value_type& x); + +
+Effects: Inserts x into the multi_index_container to which +the index belongs if + +Returns: The return value is a pair p. p.second +is true 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: Inserts x into the multi_index_container to which +the index belongs if + +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 to value_type. +first and last are not iterators into any +index of the multi_index_container to which this index belongs. +last is reachable from first.
+Effects: +
+iterator hint=end();
+while(first!=last)hint=insert(hint,*first++);
+
+Complexity: 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 by position.
+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)), where m 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)), where m 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 value x to the element pointed +to by position into the multi_index_container to which +the index belongs if, for the value x + +Postconditions: Validity of 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 the multi_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: Calls mod(e) where e is the element +pointed to by position and rearranges *position into +all the indices of the multi_index_container. Rearrangement is successful if + +If the rearrangement fails, the element is erased.
+Postconditions: Validity of position 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 possibly mod), then +the element pointed to by position is erased. +
+ + +template<typename Modifier> bool modify_key(iterator position,Modifier mod); + +
+Requires: key_from_value is a read/write +Key Extractor +from value_type. Modifier is a model of + +Unary Function accepting arguments of type +key_type&. position is a valid dereferenceable +iterator of the index.
+Effects: Calls mod(k) where k is the key +obtained by the internal KeyFromValue object of the index from +the element pointed to by position, and rearranges +*position into all the indices of the multi_index_container. +Rearrangement is successful if + +If the rearrangement fails, the element is erased.
+Postconditions:Validity of position 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 possibly mod), then +the element pointed to by position is erased. +
+ +

Observers

+ +

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. +
+ +

Set operations

+ +

+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 +

    +
  1. CompatibleCompare is a + + Binary Predicate over (Key, + CompatibleKey),
  2. +
  3. CompatibleCompare is a + + Binary Predicate over (CompatibleKey, + Key),
  4. +
  5. if c_comp(ck,k1) then !c_comp(k1,ck),
  6. +
  7. if !c_comp(ck,k1) and !comp(k1,k2) then + !c_comp(ck,k2),
  8. +
  9. if !c_comp(k1,ck) and !comp(k2,k1) then + !c_comp(k2,ck),
  10. +
+for every 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, or end() 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 of key_compare.
+Effects: Returns a pointer to an element whose key is equivalent to +x, or end() 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 to x.
+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 of key_compare.
+Effects: Returns the number of elements with key equivalent to x.
+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 than x, or end() 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 of key_compare.
+Effects: Returns an iterator pointing to the first element with +key not less than x, or end() 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 than x, or end() 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 of key_compare.
+Effects: Returns an iterator pointing to the first element with +key greater than x, or end() 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 to make_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 of key_compare.
+Effects: Equivalent to +make_pair(lower_bound(x,comp),upper_bound(x,comp)).
+Complexity: O(log(n)).
+
+ + +

Range operations

+ +

+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 +

    +
  1. LowerBounder is a + + Predicate over Key,
  2. +
  3. if lower(k1) and !comp(k2,k1) then + lower(k2),
  4. +
+for every lower of type LowerBounder, +comp of type Compare, and k1, +k2 of type Key. Similarly, an upper bounder +is a type UpperBounder such that +
    +
  1. UpperBounder is a + + Predicate over Key,
  2. +
  3. if upper(k1) and !comp(k1,k2) then + upper(k2),
  4. +
+for every 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 and UpperBounder are +a lower and upper bounder of key_compare, respectively.
+Effects: Returns a pair of iterators pointing to the beginning and one +past the end of the subsequence of elements satisfying lower and +upper simultaneously. If no such elements exist, the iterators +both point to the first element satisfying lower, or else +are equal to end() if this latter element does not exist.
+Complexity: O(log(n)).
+Variants: In place of lower or upper (or both), +the singular value boost::multi_index::unbounded can be +provided. This acts as a predicate which all values of type key_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.MultiIndex Documentation - Sequenced indices reference + + + + +

c++boost.gif (8819 bytes)Boost.MultiIndex Sequenced indices reference

+ + + +
+ +
+ +

Contents

+ + + +

+Header + +"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. +

+ +

+Header + +"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

+ +

+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: +

+Having these restrictions into account, sequenced indices are models +of +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
+
+ +

Complexity signature

+ +

+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: +

+

+ +

Instantiation types

+ +

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: +

+TagList must be an instantiation of +tag. +

+ +

Constructors, copy and assignment

+ +

+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: +
+a=b;
+
+where a and b are the multi_index_container +objects to which *this and x 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 to value_type. +first and last are not iterators into any +index of the multi_index_container to which this index belongs. +last is reachable from first.
+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);
+
+
+ +

Capacity operations

+ +void resize(size_type n,const value_type& x=value_type()); + +
+Effects: +
+if(n>size())insert(end(),n-size(),x);
+else if(n<size())erase(begin()+n,end());
+
+Note: If an expansion is requested, the size of the index is not guaranteed +to be n after this operation (other indices may ban insertions.) +
+ +

Modifiers

+ +std::pair<iterator,bool> push_front(const value_type& x); + +
+Effects: Inserts x at the beginning of the sequence if +no other index of the multi_index_container bans the insertion.
+Returns: The return value is a pair p. p.second +is true 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 the multi_index_container bans the insertion.
+Returns: The return value is a pair p. p.second +is true 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: Inserts x before position if insertion +is allowed by all other indices of the multi_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 to value_type. +first and last are not iterators into any +index of the multi_index_container to which this index belongs. +last is reachable from first.
+Effects: +
+while(first!=last)insert(position,*first++);
+
+Complexity: O(m*I(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 by position.
+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)), where m 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 value x to the element pointed +to by position into the multi_index_container to which +the index belongs if replacing is allowed by all other indices of the +multi_index_container.
+Postconditions: Validity of 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 the multi_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: Calls mod(e) where e is the element +pointed to by position and rearranges *position into +all the indices of the multi_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 of position 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 possibly mod), then +the element pointed to by position is erased. +
+ +

List operations

+ +

+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 of x before position, +in the same order as they were in x. Those elements succesfully +inserted are erased from x.
+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 iterator x.
+Effects: Inserts the element pointed to by i 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 and last are valid iterators of x. +last is reachable from first. position +is not in the range [first,last).
+Effects: For each element in the range [first,last), +insertion is tried before position; if the operation is succesful, +the element is erased from x. 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())) where m 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)), where m +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)), where m +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)), where m +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)), where m +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 over value_type. +Both the index and x are sorted according to +std::less<value_type>.
+Effects: Attempts to insert every element of x into the +corresponding position of the index (according to the order). Elements +successfully inserted are erased from x. 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 of x +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 over value_type. +Both the index and x are sorted according to comp.
+Effects: Attempts to insert every element of x into the +corresponding position of the index (according to comp). +Elements successfully inserted are erased from x. 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 to comp. +Validity of iterators to the index and of non-erased elements of x +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 over value_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 over value_type.
+Effects: Sorts the index according to comp. 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 comp 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. +
+ +

Special list operations

+ +

+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 by i before +position. If position==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 and last are valid iterators of the index. +last is reachable from first. position +is not in the range [first,last).
+Effects: The range of elements [first,last) +is repositioned just before position.
+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 @@ + + + + + +Boost.MultiIndex Documentation - Tests + + + + +

c++boost.gif (8819 bytes)Boost.MultiIndex Tests

+ + + +
+ +
+ +

+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. +

+ +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Boost.MultiIndex test suite.
ProgramDescription
test_basic.cppSimple program along the lines of the employees example studied in the + tutorial.
test_capacity.cppempty, size and (sequenced indices only) + resize.
test_comparison.cppComparison between indices.
test_composite_key.cppcomposite_key and composite_key_compare.
test_conv_iterators.cppChecks convertibility of constant to non-constant iterators.
test_copy_assignment.cppVarious forms of assignment: copy, operator =, insertion, + (sequenced indices only) assign . +
test_iterators.cppConstant and non-constant iterators and their reverse variants.
test_key_extractors.cppCovers all use cases of key extractors shipped with the library.
test_list_ops.cppList-like operations particular to sequenced indices.
test_modifiers.cppChecks the family of insertion and erasing operations.
test_mpl_ops.cppShows how to take advantage of mpl_index_list in a + metaprogram.
test_projection.cppProjection of iterators among indices.
test_range.cppExercises the range facility (ordered indices only).
test_safe_mode.cppComprehensive coverage of all conditions checked in safe mode.
test_set_ops.cppSet-like operations particular to ordered indices.
test_special_list_ops.cppConvenience functions of sequenced indices not present in + std::list.
test_special_set_ops.cppChecks special lookup operations using compatible sorting criteria.
test_update.cppreplace, 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 @@ + + + + + +Boost.MultiIndex Documentation - Tutorial + + + + +

c++boost.gif (8819 bytes)Boost.MultiIndex Tutorial

+ + + +
+ +
+ +

Contents

+ + + +

Rationale

+ +

+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_containers 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::sets or std::lists. Insertion of an +element through one given index will only succeed if the uniqueness constraints of all +indices are met. +

+ +

+Namespace +

+ +

+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;
+
+ +

Introduction

+ +

+We introduce the main concepts of Boost.MultiIndex through the study of +two typical use cases. +

+ +

Multiple sorts on a single set

+ +

+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 +employees 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: +

+Of these, probably the second solution will be the one adopted by most programmers +concerned about efficiency, but it imposes the annoying burden of keeping the two +structures in sync. If the code is additionally required to be exception-safe, this +construct easily becomes unmaintainable. +

+ +

+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(). +

+ +

A bidirectional list with fast lookup

+ +

+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. +

+ +

+Index specification +

+ +

+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)> >
+  >
+>
+
+ +

Tagging

+ +

+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 typedefs nth_index and +index for referring to an index by number and by tag, respectively; +for instance, +

+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;
+
+ +

+Index types +

+ +

+Currently, Boost.MultiIndex provides the following index types: +

+The examples in the introduction exercise all of these +indices. +

+ +

+Ordered indices +

+ +

+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. +

+ +

+Unique and non-unique variants +

+ +

+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::sets while non-unique +ordered indices are similar to std::multisets. 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;
+
+ +

+Specification +

+ +

+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. +

+ +

+Key extraction +

+ +

+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: +

+As an example, consider again the definition of 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. +

+ +

Comparison predicates

+ +

+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;
+
+ +

Special lookup operations

+ +

+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());
+
+ +

Retrieval of ranges

+ +

+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())
+
+ +

Updating

+ +

+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: +

+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");
+
+ +

+Sequenced indices +

+ +

+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::lists, 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_containers 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. +

+ +

Specification

+ +

+Sequenced indices are specified with the sequenced construct: +

+ +
+sequenced<[(tag)]>
+
+ +

+The tag parameter is optional. +

+ +

List operations

+ +

+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. +

+ +

Updating

+ +

+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. +

+ +

Projection of iterators

+ +

+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. +

+ +

Complexity and exception safety

+ +

+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 + : $(BOOST_ROOT) + ; + +exe bimap + : bimap.cpp + : $(BOOST_ROOT) + ; + +exe complex_structs + : complex_structs.cpp + : $(BOOST_ROOT) + ; + +exe composite_keys + : composite_keys.cpp + : $(BOOST_ROOT) + ; + +exe memfun_key + : memfun_key.cpp + : $(BOOST_ROOT) + ; + +exe non_default_ctor + : non_default_ctor.cpp + : $(BOOST_ROOT) + ; + +exe sequenced + : sequenced.cpp + : $(BOOST_ROOT) + ; diff --git a/example/basic.cpp b/example/basic.cpp new file mode 100644 index 0000000..3e2beff --- /dev/null +++ b/example/basic.cpp @@ -0,0 +1,122 @@ +/* Boost.MultiIndex basic example. + * + * 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. + */ + +#if !defined(NDEBUG) +#define BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING +#define BOOST_MULTI_INDEX_ENABLE_SAFE_MODE +#endif + +#include +#include +#include +#include +#include +#include +#include + +using boost::multi_index_container; +using namespace boost::multi_index; + +/* an employee record holds its ID, name and age */ + +struct employee +{ + int id; + std::string name; + int age; + + employee(int id_,std::string name_,int age_):id(id_),name(name_),age(age_){} + + friend std::ostream& operator<<(std::ostream& os,const employee& e) + { + os<, BOOST_MULTI_INDEX_MEMBER(employee,int,id)>, + ordered_non_unique< + tag,BOOST_MULTI_INDEX_MEMBER(employee,std::string,name)>, + ordered_non_unique< + tag, BOOST_MULTI_INDEX_MEMBER(employee,int,age)> > +> employee_set; + +template +void print_out_by( + const MultiIndexContainer& s, + Tag* =0 /* fixes a MSVC++ 6.0 bug with implicit template function parms */ +) +{ + /* obtain a reference to the index tagged by Tag */ + + const typename boost::multi_index::index::type& i= + get(s); + + typedef typename MultiIndexContainer::value_type value_type; + + /* dump the elements of the index to cout */ + + std::copy(i.begin(),i.end(),std::ostream_iterator(std::cout)); +} + + +int main() +{ + employee_set es; + + es.insert(employee(0,"Joe",31)); + es.insert(employee(1,"Robert",27)); + es.insert(employee(2,"John",40)); + + /* next insertion will fail, as there is an employee with + * the same ID + */ + + es.insert(employee(2,"Aristotle",2387)); + + es.insert(employee(3,"Albert",20)); + es.insert(employee(4,"John",57)); + + /* list the employees sorted by ID, name and age */ + + std::cout<<"by ID"<(es); + std::cout<(es); + std::cout<(es); + std::cout< +#include +#include +#include +#include +#include + +using boost::multi_index_container; +using namespace boost::multi_index; + +/* tags for accessing both sides of a bidirectional map */ + +struct from{}; +struct to{}; + +/* The class template bidirectional_map wraps the specification + * of a bidirectional map based on multi_index_container. + */ + +template +struct bidirectional_map +{ + typedef std::pair value_type; + +#if defined(BOOST_NO_POINTER_TO_MEMBER_TEMPLATE_PARAMETERS) ||\ + defined(BOOST_MSVC)&&(BOOST_MSVC<1300) ||\ + defined(BOOST_INTEL_CXX_VERSION)&&defined(_MSC_VER)&&\ + (BOOST_INTEL_CXX_VERSION<=700) + +/* see Advanced topics: Use of member_offset for info on member<> and + * member_offset<> + */ + + BOOST_STATIC_CONSTANT(unsigned,from_offset=offsetof(value_type,first)); + BOOST_STATIC_CONSTANT(unsigned,to_offset =offsetof(value_type,second)); + + typedef multi_index_container< + value_type, + indexed_by< + ordered_unique< + tag,member_offset >, + ordered_unique< + tag, member_offset > + > + > type; + +#else + + /* A bidirectional map can be simulated as a multi_index_container + * of pairs of (FromType,ToType) with two unique indices, one + * for each member of the pair. + */ + + typedef multi_index_container< + value_type, + indexed_by< + ordered_unique< + tag,member >, + ordered_unique< + tag, member > + > + > type; + +#endif +}; + +/* a dictionary is a bidirectional map from strings to strings */ + +typedef bidirectional_map::type dictionary; + +int main() +{ + dictionary d; + + /* Fill up our microdictionary. first members Spanish, second members + * English. + */ + + d.insert(dictionary::value_type("hola","hello")); + d.insert(dictionary::value_type("adios","goodbye")); + d.insert(dictionary::value_type("rosa","rose")); + d.insert(dictionary::value_type("mesa","table")); + + + std::cout<<"enter a word"< and family instead */ + + dictionary::iterator it=get(d).find(word); + if(it!=d.end()){ + std::cout<second<<" in English"<::type it2=get<1>(d).find(word); + if(it2!=get<1>(d).end()){ + std::cout<first<<" in Spanish"<().find(word); + if(it!=d.end()){ /* found */ + + /* the second part of the element is the equivalent in English */ + + std::cout<second<<" in English"<::type it2=d.get().find(word); + if(it2!=d.get().end()){ + std::cout<first<<" in Spanish"< +#include +#include +#include +#include +#include + +using boost::multi_index_container; +using namespace boost::multi_index; + +/* This small utility that cascades two key extractors will be + * used througout the example. + */ + +template +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 + result_type operator()(Arg& arg)const + { + return key1(key2(arg)); + } + +private: + KeyExtractor1 key1; + KeyExtractor2 key2; +}; + +/* tags for accessing several indices defined below */ + +struct model{}; +struct manufacturer{}; +struct price{}; + +/* a manufacturer struct just holds the name of the manufacturer */ + +struct car_manufacturer +{ + std::string name; + + car_manufacturer(const std::string& name_):name(name_){} +}; + +/* car_model holds the model of car, its price and a pointer to the + * manufacturer. The pointer thing eliminates duplication of the same + * data among cars of the same manufacturer. + */ + +struct car_model +{ + std::string model; + const car_manufacturer* manufacturer; + int price; + + car_model( + const std::string& model_,const car_manufacturer* manufacturer_,int price_): + model(model_),manufacturer(manufacturer_),price(price_) + {} + + friend std::ostream& operator<<(std::ostream& os,const car_model& c) + { + os<name<<" "< does the work for us.) + */ + +typedef multi_index_container< + car_manufacturer, + indexed_by< + ordered_unique< + BOOST_MULTI_INDEX_MEMBER(car_manufacturer,std::string,name) + > + > +> car_manufacturer_table; + +/* Define a multi_index_container of car_models with following indices: + * - a unique index sorted by car_model::model, + * - a non-unique index sorted by car_model::manufacturer; note the + * non-standard manufacturer_extractor used. + * - a non-unique index sorted by car_model::price. + */ + +typedef multi_index_container< + car_model, + indexed_by< + ordered_unique< + tag,BOOST_MULTI_INDEX_MEMBER(car_model,std::string,model) + >, + ordered_non_unique< + tag, + key_from_key< + BOOST_MULTI_INDEX_MEMBER(car_manufacturer,const std::string,name), + BOOST_MULTI_INDEX_MEMBER( + car_model,const car_manufacturer *,manufacturer) + > + >, + ordered_non_unique< + tag,BOOST_MULTI_INDEX_MEMBER(car_model,int,price) + > + > +> car_table; + +/* We call a *view* to a multi_index_container storing pointers instead of + * actual objects. These views are used in the complex search performed + * in the program. Resorting to multi_index of pointers eliminates + * unnecessary copying of objects, and provides us with an opportunity + * to show how BOOST_MULTI_INDEX_MEMBER can be used with pointer + * type elements. + * car_table_price_view indexes (pointers to) car_models by price. + */ + +typedef multi_index_container< + const car_model*, + indexed_by< + ordered_non_unique + > +> car_table_price_view; + +/* car_table_manufacturer_view indexes (pointers to) car_models by + * manufacturer + */ + +typedef multi_index_container< + const car_model*, + indexed_by< + ordered_non_unique< + key_from_key< + BOOST_MULTI_INDEX_MEMBER(car_manufacturer,const std::string,name), + BOOST_MULTI_INDEX_MEMBER( + car_model,const car_manufacturer * const,manufacturer) + > + > + > +> car_table_manufacturer_view; + +int main() +{ + car_manufacturer_table cmt; + + /* Fill the car_manufacturer table and keep pointers to the + * elements inserted. + */ + + const car_manufacturer * cadillac= + &*(cmt.insert(car_manufacturer("Cadillac")).first); + const car_manufacturer * ford = + &*(cmt.insert(car_manufacturer("Ford")).first); + const car_manufacturer * bmw = + &*(cmt.insert(car_manufacturer("BMW")).first); + const car_manufacturer * audi = + &*(cmt.insert(car_manufacturer("Audi")).first); + + car_table ct; + + /* Fill the car_model_table. We use the previously initialized + * pointers to the elements of cmt. + */ + + ct.insert(car_model("XLR",cadillac,76200)); + ct.insert(car_model("SRX",cadillac,38690)); + ct.insert(car_model("CTS",cadillac,30695)); + ct.insert(car_model("Escalade",cadillac,54770)); + ct.insert(car_model("ESV",cadillac,57195)); + ct.insert(car_model("EXT",cadillac,52045)); + ct.insert(car_model("Deville",cadillac,45195)); + ct.insert(car_model("Seville",cadillac,46330)); + + ct.insert(car_model("ZX2",ford,15355)); + ct.insert(car_model("Thunderbird",ford,43995)); + ct.insert(car_model("Windstar",ford,35510)); + ct.insert(car_model("Focus",ford,19630)); + ct.insert(car_model("Taurus",ford,24290)); + ct.insert(car_model("Mustang",ford,39900)); + ct.insert(car_model("Crown Victoria",ford,30370)); + + ct.insert(car_model("325i",bmw,27800)); + ct.insert(car_model("545i",bmw,54300)); + ct.insert(car_model("745i",bmw,68500)); + ct.insert(car_model("M3 coupe",bmw,46500)); + ct.insert(car_model("Z4 roadster 3.0i",bmw,40250)); + ct.insert(car_model("X5 4.4i",bmw,49950)); + + ct.insert(car_model("A4 1.8T",audi,25940)); + ct.insert(car_model("TT Coupe",audi,33940)); + ct.insert(car_model("A6 3.0",audi,36640)); + ct.insert(car_model("Allroad quattro 2.7T",audi,40640)); + ct.insert(car_model("A8 L",audi,69190)); + + std::cout<<"enter a car manufacturer"<>min_price; + std::cout<<"enter a maximum price"<>max_price; + + { + /* method 1 */ + + /* find all the cars for the manufacturer given */ + + index_iterator::type ic0,ic1; + boost::tuples::tie(ic0,ic1)=get(ct).equal_range(cm); + + /* construct a view (indexed by price) with these */ + + car_table_price_view ctpv; + while(ic0!=ic1){ + ctpv.insert(&*ic0); + ++ic0; + } + + /* select the cars in the range given */ + + car_table_price_view::iterator ictpv0=ctpv.lower_bound(min_price); + car_table_price_view::iterator ictpv1=ctpv.upper_bound(max_price); + if(ictpv0==ictpv1){ + std::cout<<"no cars in the range given"<::type ic0,ic1; + ic0=get(ct).lower_bound(min_price); + ic1=get(ct).upper_bound(max_price); + + /* construct a view with these */ + + car_table_manufacturer_view ctmv; + while(ic0!=ic1){ + ctmv.insert(&*ic0); + ++ic0; + } + + /* select the cars with given manufacturer */ + + car_table_manufacturer_view::iterator ictmv0,ictmv1; + boost::tuples::tie(ictmv0,ictmv1)=ctmv.equal_range(cm); + if(ictmv0==ictmv1){ + std::cout<<"no cars in the range given"< +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace boost::multi_index; + +/* A file record maintains some info on name and size as well + * as a pointer to the directory it belongs (null meaning the root + * directory.) + */ + +struct file_entry +{ + file_entry( + std::string name_,unsigned size_,bool is_dir_,const file_entry* dir_): + name(name_),size(size_),is_dir(is_dir_),dir(dir_) + {} + + std::string name; + unsigned size; + bool is_dir; + const file_entry* dir; + + friend std::ostream& operator<<(std::ostream& os,const file_entry& f) + { + os<"; + return os; + } +}; + +/* A file system is just a multi_index_container of entries with indices on + * file and size. These indices are firstly ordered by directory, as commands + * work on a current directory basis. Composite keys are just fine to model + * this. + * NB: We use derivation here instead of simple typedef's as MSVC++ 6.0 + * chokes otherwise. Seems to be related with the complexity of the type + * generated. + */ + +struct name_key:composite_key< + file_entry, + BOOST_MULTI_INDEX_MEMBER(file_entry,const file_entry*,dir), + BOOST_MULTI_INDEX_MEMBER(file_entry,std::string,name) +>{}; + +struct size_key:composite_key< + file_entry, + BOOST_MULTI_INDEX_MEMBER(file_entry,const file_entry* const,dir), + BOOST_MULTI_INDEX_MEMBER(file_entry,unsigned,size) +>{}; + +/* see Advanced topics: composite_key in compilers without partial template + * specialization, for info on composite_key_result_less + */ + +typedef multi_index_container< + file_entry, + indexed_by< + /* primary index sorted by name (inside the same directory) */ + ordered_unique< + name_key +#if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) + ,composite_key_result_less +#endif + >, + /* secondary index sorted by size (inside the same directory) */ + ordered_non_unique< + size_key +#if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) + ,composite_key_result_less +#endif + > + > +> file_system; + +/* typedef's of the two indices of file_system */ + +typedef nth_index::type file_system_by_name; +typedef nth_index::type file_system_by_size; + +/* We build a rudimentary file system simulation out of some global + * info and a map of commands provided to the user. + */ + +static file_system fs; /* the one and only file system */ +static file_system_by_name& fs_by_name=fs; /* name index to fs */ +static file_system_by_size& fs_by_size=get<1>(fs); /* size index to fs */ +static const file_entry* current_dir=0; /* root directory */ + +/* command framework */ + +/* A command provides an execute memfun fed with the corresponding params + * (first param is stripped off as it serves to identify the command + * currently being used.) + */ + +typedef boost::tokenizer > command_tokenizer; + +class command +{ +public: + virtual ~command(){} + virtual void execute( + command_tokenizer::iterator tok1,command_tokenizer::iterator tok2)=0; +}; + +/* available commands */ + +/* cd: syntax cd [.|..|] */ + +class command_cd:public command +{ +public: + virtual void execute( + command_tokenizer::iterator tok1,command_tokenizer::iterator tok2) + { + if(tok1==tok2)return; + std::string dir=*tok1++; + + if(dir==".")return; + if(dir==".."){ + if(current_dir)current_dir=current_dir->dir; + return; + } + + file_system_by_name::iterator it=fs.find( + boost::make_tuple(current_dir,dir)); + if(it==fs.end()){ + std::cout<<"non-existent directory"<is_dir){ + std::cout<(std::cout,"\n")); + + return; + } + + /* list by name */ + + file_system_by_name::iterator it0,it1; + boost::tie(it0,it1)=fs.equal_range(boost::make_tuple(current_dir)); + std::copy(it0,it1,std::ostream_iterator(std::cout,"\n")); + } +}; +static command_ls ls; + +/* mkdir: syntax mkdir */ + +class command_mkdir:public command +{ +public: + virtual void execute( + command_tokenizer::iterator tok1,command_tokenizer::iterator tok2) + { + std::string dir; + if(tok1!=tok2)dir=*tok1++; + + if(dir.empty()){ + std::cout<<"missing parameter"< command_table; +static command_table cmt; + +int main() +{ + /* fill the file system with some data */ + + file_system::iterator it0,it1; + + fs.insert(file_entry("usr.cfg",240,false,0)); + fs.insert(file_entry("memo.txt",2430,false,0)); + it0=fs.insert(file_entry("dev",0,true,0)).first; + fs.insert(file_entry("tty0",128,false,&*it0)); + fs.insert(file_entry("tty1",128,false,&*it0)); + it0=fs.insert(file_entry("usr",0,true,0)).first; + it1=fs.insert(file_entry("bin",0,true,&*it0)).first; + fs.insert(file_entry("bjam",172032,false,&*it1)); + it0=fs.insert(file_entry("home",0,true,0)).first; + it1=fs.insert(file_entry("andy",0,true,&*it0)).first; + fs.insert(file_entry("logo.jpg",5345,false,&*it1)).first; + fs.insert(file_entry("foo.cpp",890,false,&*it1)).first; + fs.insert(file_entry("foo.hpp",93,false,&*it1)).first; + fs.insert(file_entry("foo.html",750,false,&*it1)).first; + fs.insert(file_entry("a.obj",12302,false,&*it1)).first; + fs.insert(file_entry(".bash_history",8780,false,&*it1)).first; + it1=fs.insert(file_entry("rachel",0,true,&*it0)).first; + fs.insert(file_entry("test.py",650,false,&*it1)).first; + fs.insert(file_entry("todo.txt",241,false,&*it1)).first; + fs.insert(file_entry(".bash_history",9510,false,&*it1)).first; + + /* fill the command table */ + + cmt["cd"] =&cd; + cmt["ls"] =&ls; + cmt["mkdir"]=&mkdir; + + /* main looop */ + + for(;;){ + /* print out the current directory and the prompt symbol */ + + if(current_dir)std::cout<name; + std::cout<<">"; + + /* get an input line from the user: if empty, exit the program */ + + std::string com; + std::getline(std::cin,com); + command_tokenizer tok(com,boost::char_separator(" \t\n")); + if(tok.begin()==tok.end())break; /* null command, exit */ + + /* select the corresponding command and execute it */ + + command_table::iterator it=cmt.find(*tok.begin()); + if(it==cmt.end()){ + std::cout<<"invalid command"<second->execute(++tok.begin(),tok.end()); + } + + return 0; +} diff --git a/example/memfun_key.cpp b/example/memfun_key.cpp new file mode 100644 index 0000000..c5183cc --- /dev/null +++ b/example/memfun_key.cpp @@ -0,0 +1,76 @@ +/* Boost.MultiIndex example of member functions used as key extractors. + * + * 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. + */ + +#if !defined(NDEBUG) +#define BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING +#define BOOST_MULTI_INDEX_ENABLE_SAFE_MODE +#endif + +#include +#include +#include +#include +#include + +using namespace boost::multi_index; + +/* A name record consists of the given name (e.g. "Charlie") + * and the family name (e.g. "Brown"). The full name, calculated + * by name_record::name() is laid out in the "phonebook order" + * family name + given_name. + */ + +struct name_record +{ + name_record(std::string given_name,std::string family_name): + given_name(given_name),family_name(family_name) + {} + + std::string name()const + { + std::string str=family_name; + str+=" "; + str+=given_name; + return str; + } + +private: + std::string given_name; + std::string family_name; +}; + +/* multi_index_container with only one index based on name_record::name() */ + +typedef multi_index_container< + name_record, + indexed_by< + ordered_unique< + BOOST_MULTI_INDEX_CONST_MEM_FUN(name_record,std::string,name) + > + > +> name_record_set; + +int main() +{ + name_record_set ns; + + ns.insert(name_record("Joe","Smith")); + ns.insert(name_record("Robert","Nightingale")); + ns.insert(name_record("Robert","Brown")); + ns.insert(name_record("Marc","Tuxedo")); + + /* list the names in ns in phonebook order */ + + for(name_record_set::iterator it=ns.begin();it!=ns.end();++it){ + std::cout<name()< +#include +#include +#include +#include +#include + +using boost::multi_index_container; +using namespace boost::multi_index; + +/* modulo_less order numbers according to their division residual. + * For instance, if modulo==10 then 22 is less than 15 as 22%10==2 and + * 15%10==5. + */ + +template +struct modulo_less +{ + modulo_less(IntegralType m):modulo(m){} + + bool operator()(IntegralType x,IntegralType y)const + { + return (x%modulo)<(y%modulo); + } + +private: + IntegralType modulo; +}; + +/* multi_index_container of unsigned ints holding a "natural" index plus + * an ordering based on modulo_less. + */ + +typedef multi_index_container< + unsigned int, + indexed_by< + ordered_unique >, + ordered_non_unique, modulo_less > + > +> modulo_indexed_set; + +int main() +{ + /* define a modulo_indexed_set with modulo==10 */ + + modulo_indexed_set::ctor_args_list args_list= + boost::make_tuple( + /* ctor_args for index #0 is default constructible */ + nth_index::type::ctor_args(), + + /* first parm is key_from_value, second is our sought for key_compare */ + boost::make_tuple(identity(),modulo_less(10)) + ); + + modulo_indexed_set m(args_list); + /* this could have be written online without the args_list variable, + * left as it is for explanatory purposes. */ + + /* insert some numbers */ + + unsigned int numbers[]={0,1,20,40,33,68,11,101,60,34,88,230,21,4,7,17}; + const std::size_t numbers_length(sizeof(numbers)/sizeof(numbers[0])); + + m.insert(&numbers[0],&numbers[numbers_length]); + + /* lists all numbers in order, along with their "equivalence class", that is, + * the equivalent numbers under modulo_less + */ + + for(modulo_indexed_set::iterator it=m.begin();it!=m.end();++it){ + std::cout<<*it<<" -> ( "; + + nth_index::type::iterator it0,it1; + boost::tie(it0,it1)=get<1>(m).equal_range(*it); + std::copy(it0,it1,std::ostream_iterator(std::cout," ")); + + std::cout<<")"< +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using boost::multi_index_container; +using namespace boost::multi_index; + +/* text_container holds words as inserted and also keep them indexed + * by dictionary order. + */ + +typedef multi_index_container< + std::string, + indexed_by< + sequenced<>, + ordered_non_unique > + > +> text_container; + +/* ordered index */ + +typedef nth_index::type ordered_text; + +typedef boost::tokenizer > text_tokenizer; + +int main() +{ + std::string text= + "Alice was beginning to get very tired of sitting by her sister on the " + "bank, and of having nothing to do: once or twice she had peeped into the " + "book her sister was reading, but it had no pictures or conversations in " + "it, 'and what is the use of a book,' thought Alice 'without pictures or " + "conversation?'"; + + /* feed the text into the container */ + + text_container tc; + text_tokenizer tok(text,boost::char_separator(" \t\n.,;:!?'\"-")); + std::copy(tok.begin(),tok.end(),std::back_inserter(tc)); + + /* list all words in alphabetical order along with their number + * of occurrences + */ + + ordered_text& ot=get<1>(tc); + for(ordered_text::iterator it=ot.begin();it!=ot.end();){ + std::cout<(std::cout," ")); + std::cout<(std::cout," ")); + std::cout< /* keep it first to prevent nasty warns in MSVC */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* A composite key stores n key extractors and "computes" the + * result on a given value as a packed reference to the value and + * the composite key itself. Actual invocations to the component + * key extractors are lazily performed on comparison time. + * As the other key extractors in Boost.MultiIndex, composite_key + * is overloaded to work on chained pointers to T and reference_wrappers + * of T. + * composite_key_compare is overloaded to enable comparisons between + * composite_key_results and tuples of values. Comparison is done + * lexicographically on on the maximum common number of elements of the + * operands. This allows searching for incomplete keys + */ + +/* This user_definable macro limits the number of elements of a composite + * key; useful for shortening resulting symbol names (MSVC++ 6.0, for + * instance has problems coping with very long symbol names.) + * NB: This cannot exceed the maximum number of arguments of + * boost::tuple. In Boost 1.31, the limit is 10. + */ + +#if !defined(BOOST_MULTI_INDEX_LIMIT_COMPOSITE_KEY_SIZE) +#if defined(BOOST_MSVC)&&(BOOST_MSVC<1300) +#define BOOST_MULTI_INDEX_LIMIT_COMPOSITE_KEY_SIZE 5 +#else +#define BOOST_MULTI_INDEX_LIMIT_COMPOSITE_KEY_SIZE 10 +#endif +#endif + +/* maximum number of key extractors in a composite key */ + +#if BOOST_MULTI_INDEX_LIMIT_COMPOSITE_KEY_SIZE<10 /* max length of a tuple */ +#define BOOST_MULTI_INDEX_COMPOSITE_KEY_SIZE \ + BOOST_MULTI_INDEX_LIMIT_COMPOSITE_KEY_SIZE +#else +#define BOOST_MULTI_INDEX_COMPOSITE_KEY_SIZE 10 +#endif + +/* BOOST_PP_ENUM of BOOST_MULTI_INDEX_COMPOSITE_KEY_SIZE elements */ + +#define BOOST_MULTI_INDEX_CK_ENUM(macro,data) \ + BOOST_PP_ENUM(BOOST_MULTI_INDEX_COMPOSITE_KEY_SIZE,macro,data) + +/* BOOST_PP_ENUM_PARAMS of BOOST_MULTI_INDEX_COMPOSITE_KEY_SIZE elements */ + +#define BOOST_MULTI_INDEX_CK_ENUM_PARAMS(param) \ + BOOST_PP_ENUM_PARAMS(BOOST_MULTI_INDEX_COMPOSITE_KEY_SIZE,param) + +/* if n==0 -> text0 + * otherwise -> textn=tuples::null_type + */ + +#define BOOST_MULTI_INDEX_CK_TEMPLATE_PARM(z,n,text) \ + typename BOOST_PP_CAT(text,n) BOOST_PP_EXPR_IF(n,=tuples::null_type) + +/* const textn& kn=textn() */ + +#define BOOST_MULTI_INDEX_CK_CTOR_ARG(z,n,text) \ + const BOOST_PP_CAT(text,n)& BOOST_PP_CAT(k,n) = BOOST_PP_CAT(text,n)() + +/* typename list(0)::type */ + +#define BOOST_MULTI_INDEX_CK_APPLY_METAFUNCTION_N(z,n,list) \ + BOOST_DEDUCED_TYPENAME BOOST_PP_LIST_AT(list,0)< \ + BOOST_PP_LIST_AT(list,1),n \ + >::type + +namespace boost{ + +template class reference_wrapper; /* fwd decl. */ + +namespace multi_index{ + +namespace detail{ + +/* nth_composite_key_less:: yields std::less + * where result_type is the result_type of the nth key extractor of + * CompositeKey. If N >= the length of CompositeKey, it yields + * tuples::null_type. + * Similar thing for nth_composite_key_greater. + */ + +template +struct nth_key_from_value +{ + typedef typename CompositeKey::key_extractor_tuple key_extractor_tuple; + typedef typename prevent_eti< + tuples::element, + typename mpl::apply_if_c< + N::value, + tuples::element, + mpl::identity + >::type + >::type type; +}; + +template +struct key_std_less +{ + typedef std::less type; +}; + +template<> +struct key_std_less +{ + typedef tuples::null_type type; +}; + +template +struct nth_composite_key_less +{ + typedef typename nth_key_from_value::type key_from_value; + typedef typename key_std_less::type type; +}; + +template +struct key_std_greater +{ + typedef std::greater type; +}; + +template<> +struct key_std_greater +{ + typedef tuples::null_type type; +}; + +template +struct nth_composite_key_greater +{ + typedef typename nth_key_from_value::type key_from_value; + typedef typename key_std_greater::type type; +}; + +/* Metaprogramming machinery to compare composite_key_results between + * them and with tuples of values. + * equals_* computes equality of two tuple objects x,y with the same + * length, defined as + * + * xi==yi for all i in [0,...,min(length(x),length(y))). + * + * less_* accepts operands of different lenghts and computes the + * following less-than relation: + * + * !(xi +struct equals_ckey_ckey; /* fwd decl. */ + +template +struct equals_ckey_ckey_terminal +{ + static bool compare( + const KeyCons1&,const Value1&, + const KeyCons2&,const Value2&) + { + return true; + } +}; + +template +struct equals_ckey_ckey_normal +{ + static bool compare( + const KeyCons1& c0,const Value1& v0, + const KeyCons2& c1,const Value2& v1) + { + if(!(c0.get_head()(v0)==c1.get_head()(v1)))return false; + return equals_ckey_ckey< + BOOST_DEDUCED_TYPENAME KeyCons1::tail_type,Value1, + BOOST_DEDUCED_TYPENAME KeyCons2::tail_type,Value2 + >::compare(c0.get_tail(),v0,c1.get_tail(),v1); + } +}; + +template +struct equals_ckey_ckey: + mpl::if_< + mpl::or_< + is_same, + is_same + >, + equals_ckey_ckey_terminal, + equals_ckey_ckey_normal + >::type +{ +}; + +template +struct equals_ckey_cval; /* fwd decl. */ + +template +struct equals_ckey_cval_terminal +{ + static bool compare(const KeyCons&,const Value&,const ValCons&) + { + return true; + } + + static bool compare(const ValCons&,const KeyCons&,const Value&) + { + return true; + } +}; + +template +struct equals_ckey_cval_normal +{ + static bool compare(const KeyCons& c,const Value& v,const ValCons& vc) + { + if(!(c.get_head()(v)==vc.get_head()))return false; + return equals_ckey_cval< + BOOST_DEDUCED_TYPENAME KeyCons::tail_type,Value, + BOOST_DEDUCED_TYPENAME ValCons::tail_type + >::compare(c.get_tail(),v,vc.get_tail()); + } + + static bool compare(const ValCons& vc,const KeyCons& c,const Value& v) + { + if(!(vc.get_head()==c.get_head()(v)))return false; + return equals_ckey_cval< + BOOST_DEDUCED_TYPENAME KeyCons::tail_type,Value, + BOOST_DEDUCED_TYPENAME ValCons::tail_type + >::compare(vc.get_tail(),c.get_tail(),v); + } +}; + +template +struct equals_ckey_cval: + mpl::if_< + mpl::or_< + is_same, + is_same + >, + equals_ckey_cval_terminal, + equals_ckey_cval_normal + >::type +{ +}; + +template +struct less_ckey_ckey; /* fwd decl. */ + +template +struct less_ckey_ckey_terminal +{ + static bool compare( + const KeyCons1&,const Value1&,const KeyCons2&,const Value2&) + { + return false; + } +}; + +template +struct less_ckey_ckey_normal +{ + static bool compare( + const KeyCons1& c0,const Value1& v0, + const KeyCons2& c1,const Value2& v1) + { + if(c0.get_head()(v0)::compare(c0.get_tail(),v0,c1.get_tail(),v1); + } +}; + +template +struct less_ckey_ckey: + mpl::if_< + mpl::or_< + is_same, + is_same + >, + less_ckey_ckey_terminal, + less_ckey_ckey_normal + >::type +{ +}; + +template +struct less_ckey_cval; /* fwd decl. */ + +template +struct less_ckey_cval_terminal +{ + static bool compare(const KeyCons&,const Value&,const ValCons&) + { + return false; + } + + static bool compare(const ValCons&,const KeyCons&,const Value&) + { + return false; + } +}; + +template +struct less_ckey_cval_normal +{ + static bool compare(const KeyCons& c,const Value& v,const ValCons& vc) + { + if(c.get_head()(v)::compare(c.get_tail(),v,vc.get_tail()); + } + + static bool compare(const ValCons& vc,const KeyCons& c,const Value& v) + { + if(vc.get_head()::compare(vc.get_tail(),c.get_tail(),v); + } +}; + +template +struct less_ckey_cval: + mpl::if_< + mpl::or_< + is_same, + is_same + >, + less_ckey_cval_terminal, + less_ckey_cval_normal + >::type +{ +}; + +template +< + typename KeyCons1,typename Value1, + typename KeyCons2, typename Value2, + typename CompareCons +> +struct compare_ckey_ckey; /* fwd decl. */ + +template +< + typename KeyCons1,typename Value1, + typename KeyCons2, typename Value2, + typename CompareCons +> +struct compare_ckey_ckey_terminal +{ + static bool compare( + const KeyCons1&,const Value1&, + const KeyCons2&,const Value2&, + const CompareCons&) + { + return false; + } +}; + +template +< + typename KeyCons1,typename Value1, + typename KeyCons2, typename Value2, + typename CompareCons +> +struct compare_ckey_ckey_normal +{ + static bool compare( + const KeyCons1& c0,const Value1& v0, + const KeyCons2& c1,const Value2& v1, + const CompareCons& comp) + { + if(comp.get_head()(c0.get_head()(v0),c1.get_head()(v1)))return true; + if(comp.get_head()(c1.get_head()(v1),c0.get_head()(v0)))return false; + return compare_ckey_ckey< + BOOST_DEDUCED_TYPENAME KeyCons1::tail_type,Value1, + BOOST_DEDUCED_TYPENAME KeyCons2::tail_type,Value2, + BOOST_DEDUCED_TYPENAME CompareCons::tail_type + >::compare(c0.get_tail(),v0,c1.get_tail(),v1,comp.get_tail()); + } +}; + +template +< + typename KeyCons1,typename Value1, + typename KeyCons2, typename Value2, + typename CompareCons +> +struct compare_ckey_ckey: + mpl::if_< + mpl::or_< + is_same, + is_same + >, + compare_ckey_ckey_terminal, + compare_ckey_ckey_normal + >::type +{ +}; + +template +< + typename KeyCons,typename Value, + typename ValCons,typename CompareCons +> +struct compare_ckey_cval; /* fwd decl. */ + +template +< + typename KeyCons,typename Value, + typename ValCons,typename CompareCons +> +struct compare_ckey_cval_terminal +{ + static bool compare( + const KeyCons&,const Value&,const ValCons&,const CompareCons&) + { + return false; + } + + static bool compare( + const ValCons&,const KeyCons&,const Value&,const CompareCons&) + { + return false; + } +}; + +template +< + typename KeyCons,typename Value, + typename ValCons,typename CompareCons +> +struct compare_ckey_cval_normal +{ + static bool compare( + const KeyCons& c,const Value& v,const ValCons& vc, + const CompareCons& comp) + { + if(comp.get_head()(c.get_head()(v),vc.get_head()))return true; + if(comp.get_head()(vc.get_head(),c.get_head()(v)))return false; + return compare_ckey_cval< + BOOST_DEDUCED_TYPENAME KeyCons::tail_type,Value, + BOOST_DEDUCED_TYPENAME ValCons::tail_type, + BOOST_DEDUCED_TYPENAME CompareCons::tail_type + >::compare(c.get_tail(),v,vc.get_tail(),comp.get_tail()); + } + + static bool compare( + const ValCons& vc,const KeyCons& c,const Value& v, + const CompareCons& comp) + { + if(comp.get_head()(vc.get_head(),c.get_head()(v)))return true; + if(comp.get_head()(c.get_head()(v),vc.get_head()))return false; + return compare_ckey_cval< + BOOST_DEDUCED_TYPENAME KeyCons::tail_type,Value, + BOOST_DEDUCED_TYPENAME ValCons::tail_type, + BOOST_DEDUCED_TYPENAME CompareCons::tail_type + >::compare(vc.get_tail(),c.get_tail(),v,comp.get_tail()); + } +}; + +template +< + typename KeyCons,typename Value, + typename ValCons,typename CompareCons +> +struct compare_ckey_cval: + mpl::if_< + mpl::or_< + is_same, + is_same + >, + compare_ckey_cval_terminal, + compare_ckey_cval_normal + >::type +{ +}; + +} /* namespace multi_index::detail */ + +/* composite_key_result */ + +template +struct composite_key_result +{ + typedef CompositeKey composite_key_type; + typedef typename composite_key_type::value_type value_type; + + composite_key_result( + const composite_key_type& composite_key_,const value_type& value_): + composite_key(composite_key_),value(value_) + {} + + const composite_key_type& composite_key; + const value_type& value; +}; + +/* composite_key */ + +template< + typename Value, + BOOST_MULTI_INDEX_CK_ENUM(BOOST_MULTI_INDEX_CK_TEMPLATE_PARM,KeyFromValue) +> +struct composite_key: + private tuple +{ +private: + typedef tuple super; + +public: + typedef super key_extractor_tuple; + typedef Value value_type; + typedef composite_key_result result_type; + + composite_key( + BOOST_MULTI_INDEX_CK_ENUM(BOOST_MULTI_INDEX_CK_CTOR_ARG,KeyFromValue)): + super(BOOST_MULTI_INDEX_CK_ENUM_PARAMS(k)) + {} + + composite_key(const key_extractor_tuple& x):super(x){} + + const key_extractor_tuple& key_extractors()const{return *this;} + key_extractor_tuple& key_extractors(){return *this;} + + template + result_type operator()(const ChainedPtr& x)const + { + return operator()(*x); + } + + result_type operator()(const value_type& x)const + { + return result_type(*this,x); + } + + result_type operator()(const reference_wrapper& x)const + { + return result_type(*this,x.get()); + } + + result_type operator()(const reference_wrapper& x)const + { + return result_type(*this,x.get()); + } +}; + +/* comparison operators */ + +/* == */ + +template +inline bool operator==( + const composite_key_result& x, + const composite_key_result& y) +{ + typedef typename CompositeKey1::key_extractor_tuple key_extractor_tuple1; + typedef typename CompositeKey1::value_type value_type1; + typedef typename CompositeKey2::key_extractor_tuple key_extractor_tuple2; + typedef typename CompositeKey2::value_type value_type2; + + BOOST_STATIC_ASSERT( + tuples::length::value== + tuples::length::value); + + return detail::equals_ckey_ckey< + key_extractor_tuple1,value_type1, + key_extractor_tuple2,value_type2 + >::compare( + x.composite_key.key_extractors(),x.value, + y.composite_key.key_extractors(),y.value); +} + +template< + typename CompositeKey, + BOOST_MULTI_INDEX_CK_ENUM_PARAMS(typename Value) +> +inline bool operator==( + const composite_key_result& x, + const tuple& y) +{ + typedef typename CompositeKey::key_extractor_tuple key_extractor_tuple; + typedef typename CompositeKey::value_type value_type; + typedef tuple key_tuple; + + BOOST_STATIC_ASSERT( + tuples::length::value== + tuples::length::value); + + return detail::equals_ckey_cval:: + compare(x.composite_key.key_extractors(),x.value,y); +} + +template +< + BOOST_MULTI_INDEX_CK_ENUM_PARAMS(typename Value), + typename CompositeKey +> +inline bool operator==( + const tuple& x, + const composite_key_result& y) +{ + typedef typename CompositeKey::key_extractor_tuple key_extractor_tuple; + typedef typename CompositeKey::value_type value_type; + typedef tuple key_tuple; + + BOOST_STATIC_ASSERT( + tuples::length::value== + tuples::length::value); + + return detail::equals_ckey_cval:: + compare(x,y.composite_key.key_extractors(),y.value); +} + +/* < */ + +template +inline bool operator<( + const composite_key_result& x, + const composite_key_result& y) +{ + typedef typename CompositeKey1::key_extractor_tuple key_extractor_tuple1; + typedef typename CompositeKey1::value_type value_type1; + typedef typename CompositeKey2::key_extractor_tuple key_extractor_tuple2; + typedef typename CompositeKey2::value_type value_type2; + + return detail::less_ckey_ckey< + key_extractor_tuple1,value_type1, + key_extractor_tuple2,value_type2 + >::compare( + x.composite_key.key_extractors(),x.value, + y.composite_key.key_extractors(),y.value); +} + +template +< + typename CompositeKey, + BOOST_MULTI_INDEX_CK_ENUM_PARAMS(typename Value) +> +inline bool operator<( + const composite_key_result& x, + const tuple& y) +{ + typedef typename CompositeKey::key_extractor_tuple key_extractor_tuple; + typedef typename CompositeKey::value_type value_type; + typedef tuple key_tuple; + + return detail::less_ckey_cval:: + compare(x.composite_key.key_extractors(),x.value,y); +} + +template +< + BOOST_MULTI_INDEX_CK_ENUM_PARAMS(typename Value), + typename CompositeKey +> +inline bool operator<( + const tuple& x, + const composite_key_result& y) +{ + typedef typename CompositeKey::key_extractor_tuple key_extractor_tuple; + typedef typename CompositeKey::value_type value_type; + typedef tuple key_tuple; + + return detail::less_ckey_cval:: + compare(x,y.composite_key.key_extractors(),y.value); +} + +/* rest of comparison operators */ + +#define BOOST_MULTI_INDEX_CK_COMPLETE_COMP_OPS(t1,t2,a1,a2) \ +template inline bool operator!=(const a1& x,const a2& y) \ +{ \ + return !(x==y); \ +} \ + \ +template inline bool operator>(const a1& x,const a2& y) \ +{ \ + return y inline bool operator>=(const a1& x,const a2& y) \ +{ \ + return !(x inline bool operator<=(const a1& x,const a2& y) \ +{ \ + return !(y, + composite_key_result +) + +BOOST_MULTI_INDEX_CK_COMPLETE_COMP_OPS( + typename CompositeKey, + BOOST_MULTI_INDEX_CK_ENUM_PARAMS(typename Value), + composite_key_result, + tuple +) + +BOOST_MULTI_INDEX_CK_COMPLETE_COMP_OPS( + BOOST_MULTI_INDEX_CK_ENUM_PARAMS(typename Value), + typename CompositeKey, + tuple, + composite_key_result +) + +/* composite_key_compare */ + +template +< + BOOST_MULTI_INDEX_CK_ENUM(BOOST_MULTI_INDEX_CK_TEMPLATE_PARM,Compare) +> +struct composite_key_compare: + private tuple +{ +private: + typedef tuple super; + +public: + typedef super key_comp_tuple; + + composite_key_compare( + BOOST_MULTI_INDEX_CK_ENUM(BOOST_MULTI_INDEX_CK_CTOR_ARG,Compare)): + super(BOOST_MULTI_INDEX_CK_ENUM_PARAMS(k)) + {} + + composite_key_compare(const key_comp_tuple& x):super(x){} + + const key_comp_tuple& key_comps()const{return *this;} + key_comp_tuple& key_comps(){return *this;} + + template + bool operator()( + const composite_key_result & x, + const composite_key_result & y)const + { + typedef typename CompositeKey1::key_extractor_tuple key_extractor_tuple1; + typedef typename CompositeKey1::value_type value_type1; + typedef typename CompositeKey2::key_extractor_tuple key_extractor_tuple2; + typedef typename CompositeKey2::value_type value_type2; + + BOOST_STATIC_ASSERT( + tuples::length::value<= + tuples::length::value|| + tuples::length::value<= + tuples::length::value); + + return detail::compare_ckey_ckey< + key_extractor_tuple1,value_type1, + key_extractor_tuple2,value_type2, + key_comp_tuple + >::compare( + x.composite_key.key_extractors(),x.value, + y.composite_key.key_extractors(),y.value, + key_comps()); + } + + template + < + typename CompositeKey, + BOOST_MULTI_INDEX_CK_ENUM_PARAMS(typename Value) + > + bool operator()( + const composite_key_result& x, + const tuple& y)const + { + typedef typename CompositeKey::key_extractor_tuple key_extractor_tuple; + typedef typename CompositeKey::value_type value_type; + typedef tuple key_tuple; + + BOOST_STATIC_ASSERT( + tuples::length::value<= + tuples::length::value|| + tuples::length::value<= + tuples::length::value); + + return detail::compare_ckey_cval< + key_extractor_tuple,value_type, + key_tuple,key_comp_tuple + >::compare(x.composite_key.key_extractors(),x.value,y,key_comps()); + } + + template + < + BOOST_MULTI_INDEX_CK_ENUM_PARAMS(typename Value), + typename CompositeKey + > + bool operator()( + const tuple& x, + const composite_key_result& y)const + { + typedef typename CompositeKey::key_extractor_tuple key_extractor_tuple; + typedef typename CompositeKey::value_type value_type; + typedef tuple key_tuple; + + BOOST_STATIC_ASSERT( + tuples::length::value<= + tuples::length::value|| + tuples::length::value<= + tuples::length::value); + + return detail::compare_ckey_cval< + key_extractor_tuple,value_type, + key_tuple,key_comp_tuple + >::compare(x,y.composite_key.key_extractors(),y.value,key_comps()); + } +}; + +/* composite_key_compare_less is merely a composite_key_compare + * instantiation with the corresponding std::less<> comparison + * predicates for each key extractor. Useful as a substitute for + * std::less when the compiler does not + * support partial specialization. + * Same with composite_key_compare_greater. + */ + +#define BOOST_MULTI_INDEX_CK_RESULT_LESS_SUPER \ +composite_key_compare< \ + BOOST_MULTI_INDEX_CK_ENUM( \ + BOOST_MULTI_INDEX_CK_APPLY_METAFUNCTION_N, \ + /* the argument is a PP list */ \ + (detail::nth_composite_key_less, \ + (BOOST_DEDUCED_TYPENAME CompositeKeyResult::composite_key_type, \ + BOOST_PP_NIL))) \ + > + +template +struct composite_key_result_less: +BOOST_MULTI_INDEX_PRIVATE_IF_USING_DECL_FOR_TEMPL_FUNCTIONS +BOOST_MULTI_INDEX_CK_RESULT_LESS_SUPER +{ +private: + typedef BOOST_MULTI_INDEX_CK_RESULT_LESS_SUPER super; + +public: + typedef CompositeKeyResult first_argument_type; + typedef first_argument_type second_argument_type; + typedef bool result_type; + + using super::operator(); +}; + +#define BOOST_MULTI_INDEX_CK_RESULT_GREATER_SUPER \ +composite_key_compare< \ + BOOST_MULTI_INDEX_CK_ENUM( \ + BOOST_MULTI_INDEX_CK_APPLY_METAFUNCTION_N, \ + /* the argument is a PP list */ \ + (detail::nth_composite_key_greater, \ + (BOOST_DEDUCED_TYPENAME CompositeKeyResult::composite_key_type, \ + BOOST_PP_NIL))) \ + > + +template +struct composite_key_result_greater: +BOOST_MULTI_INDEX_PRIVATE_IF_USING_DECL_FOR_TEMPL_FUNCTIONS +BOOST_MULTI_INDEX_CK_RESULT_GREATER_SUPER +{ +private: + typedef BOOST_MULTI_INDEX_CK_RESULT_GREATER_SUPER super; + +public: + typedef CompositeKeyResult first_argument_type; + typedef first_argument_type second_argument_type; + typedef bool result_type; + + using super::operator(); +}; + +} /* namespace multi_index */ + +} /* namespace boost */ + +/* Specialization of std::less and std::greater for composite_key_results + * enabling comparison with tuples of values. + */ + +#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) +namespace std{ + +template +struct less >: + boost::multi_index::composite_key_result_less< + boost::multi_index::composite_key_result + > +{ +}; + +template +struct greater >: + boost::multi_index::composite_key_result_greater< + boost::multi_index::composite_key_result + > +{ +}; + +} /* namespace std */ +#endif + +#undef BOOST_MULTI_INDEX_CK_RESULT_LESS_SUPER +#undef BOOST_MULTI_INDEX_CK_RESULT_GREATER_SUPER +#undef BOOST_MULTI_INDEX_CK_COMPLETE_COMP_OPS +#undef BOOST_MULTI_INDEX_CK_APPLY_METAFUNCTION_N +#undef BOOST_MULTI_INDEX_CK_CTOR_ARG +#undef BOOST_MULTI_INDEX_CK_TEMPLATE_PARM +#undef BOOST_MULTI_INDEX_CK_ENUM_PARAMS +#undef BOOST_MULTI_INDEX_CK_ENUM +#undef BOOST_MULTI_INDEX_COMPOSITE_KEY_SIZE + +#endif diff --git a/include/boost/multi_index/detail/access_specifier.hpp b/include/boost/multi_index/detail/access_specifier.hpp new file mode 100644 index 0000000..5d367b0 --- /dev/null +++ b/include/boost/multi_index/detail/access_specifier.hpp @@ -0,0 +1,39 @@ +/* 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. + */ + +#ifndef BOOST_MULTI_INDEX_DETAIL_ACCESS_SPECIFIER_HPP +#define BOOST_MULTI_INDEX_DETAIL_ACCESS_SPECIFIER_HPP + +#include +#include + +/* In those compilers that do not accept the member template friend syntax, + * some protected and private sections might need to be specified as + * public. + */ + +#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) +#define BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS protected +#define BOOST_MULTI_INDEX_PRIVATE_IF_MEMBER_TEMPLATE_FRIENDS private +#else +#define BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS public +#define BOOST_MULTI_INDEX_PRIVATE_IF_MEMBER_TEMPLATE_FRIENDS public +#endif + +/* GCC does not correctly support in-class using declarations for template + * functions. See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=9810 + */ + +#if BOOST_WORKAROUND(__GNUC__, <3)||\ + BOOST_WORKAROUND(__GNUC__,==3)&&(__GNUC_MINOR__<4) +#define BOOST_MULTI_INDEX_PRIVATE_IF_USING_DECL_FOR_TEMPL_FUNCTIONS public +#else +#define BOOST_MULTI_INDEX_PRIVATE_IF_USING_DECL_FOR_TEMPL_FUNCTIONS private +#endif + +#endif diff --git a/include/boost/multi_index/detail/allocator.hpp b/include/boost/multi_index/detail/allocator.hpp new file mode 100644 index 0000000..63bb911 --- /dev/null +++ b/include/boost/multi_index/detail/allocator.hpp @@ -0,0 +1,213 @@ +/* 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. + */ + +#ifndef BOOST_MULTI_INDEX_DETAIL_ALLOCATOR_HPP +#define BOOST_MULTI_INDEX_DETAIL_ALLOCATOR_HPP + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include +#include +#include +#include + +namespace boost{ + +namespace multi_index{ + +namespace detail{ + +/* allocator adaption layer */ + +namespace allocator{ + +/* Detects whether a given allocator is from old Dinkumware's stdlib, + * which lacks rebind and uses an ugly _Charalloc memfun as a poor + * replacement. + * Note that it does not suffice to check the Boost.Config stdlib + * macros, as the user might have passed a custom, compliant allocator. + */ + +#if defined(BOOST_DINKUMWARE_STDLIB)&&defined(BOOST_NO_STD_ALLOCATOR) + +template +struct dinkumware_defective_allocator +{ + BOOST_STATIC_CONSTANT(bool, + value=( + is_same< + Allocator, + std::allocator + >::value)); +}; + +#else + +template +struct dinkumware_defective_allocator +{ + BOOST_STATIC_CONSTANT(bool,value=false); +}; + +#endif + +/* allocator ops for Dinkumware's defective allocator */ + +template +struct dinkumware_defective_allocator_ops +{ + typedef Allocator rebound_type; + + static Type* allocate(Allocator& al,typename Allocator::size_type n) + { + return static_cast( + static_cast(al._Charalloc(n*sizeof(Type)))); + } + + static void deallocate(Allocator& al,Type* p,typename Allocator::size_type n) + { + al.deallocate(p,n); + } + + static void construct(Allocator&,Type* p,const Type& t) + { + new(static_cast(p))Type(t); + } + + static void destroy(Allocator&,Type* p) + { + (static_cast(p))->~Type(); + } +}; + +/* allocator ops for compliant allocators */ + +#if BOOST_WORKAROUND(BOOST_MSVC,<1300) +/* Workaround for a problem in MSVC with dependent template typedefs + * when doing rebinding of allocators. + * Modeled after (thanks, Aleksey!) + */ + +template +struct msvc_rebind +{ + template struct fake_allocator:Allocator{}; + template<> struct fake_allocator + { + template struct rebind{}; + }; + + template + struct result: + fake_allocator::value>:: + template rebind + { + }; +}; +#endif + +template +struct compliant_allocator_ops +{ + +#if BOOST_WORKAROUND(BOOST_MSVC,<1300) + typedef typename msvc_rebind:: + template result::other rebound_type; +#else + typedef typename Allocator:: + BOOST_NESTED_TEMPLATE rebind::other rebound_type; +#endif + + static Type* allocate(Allocator& al,typename Allocator::size_type n) + { + return al.allocate(n); + } + + static void deallocate(Allocator& al,Type* p,typename Allocator::size_type n) + { + al.deallocate(p,n); + } + + static void construct(Allocator& al,Type *p,const Type& t) + { + al.construct(p,t); + } + + static void destroy(Allocator& al,Type* p) + { + al.destroy(p); + } +}; + +template +struct allocator_ops: + mpl::if_c< + dinkumware_defective_allocator::value, + dinkumware_defective_allocator_ops, + compliant_allocator_ops + >::type +{ +}; + +/* allocator ops front end */ + +template +struct rebind_to +{ + typedef typename allocator_ops::rebound_type type; +}; + +template +Type* allocate( + Allocator& al,typename Allocator::size_type n + BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE(Type)) +{ + return allocator_ops::allocate(al,n); +} + +template +void deallocate(Allocator& al,Type* p,typename Allocator::size_type n) +{ + allocator_ops::deallocate(al,p,n); +} + +template +void construct(Allocator& al,Type* p,const Type& t) +{ + allocator_ops::construct(al,p,t); +} + +template +void destroy(Allocator& al,Type* p) +{ + allocator_ops::destroy(al,p); +} + +/* allocator-independent versions of construct and destroy */ + +template +void construct(void* p,const Type& t) +{ + new (p) Type(t); +} + +template +void destroy(const Type* p) +{ + p->~Type(); +} + +} /* namespace multi_index::detail::allocator */ + +} /* namespace multi_index::detail */ + +} /* namespace multi_index */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/multi_index/detail/auto_space.hpp b/include/boost/multi_index/detail/auto_space.hpp new file mode 100644 index 0000000..d5d6d8e --- /dev/null +++ b/include/boost/multi_index/detail/auto_space.hpp @@ -0,0 +1,64 @@ +/* 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. + */ + +#ifndef BOOST_MULTI_INDEX_DETAIL_AUTO_SPACE_HPP +#define BOOST_MULTI_INDEX_DETAIL_AUTO_SPACE_HPP + +#include +#include +#include + +namespace boost{ + +namespace multi_index{ + +namespace detail{ + +/* auto_space provides uninitialized space suitably to store + * a given number of elements of a given type. + */ + +/* NB: it is not clear whether using an allocator to handle + * zero-sized arrays of elements is conformant or not. GCC 3.3.1 + * and prior fail here, other stdlibs handle the issue gracefully. + * To be on the safe side, the case n==0 is given special treatment. + * References: + * GCC Bugzilla, "standard allocator crashes when deallocating segment + * "of zero length", http://gcc.gnu.org/bugzilla/show_bug.cgi?id=14176 + * C++ Standard Library Defect Report List (Revision 28), issue 199 + * "What does allocate(0) return?", + * http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/lwg-defects.html#199 + */ + +template > +struct auto_space:private noncopyable +{ + explicit auto_space(const Allocator& al=Allocator(),std::size_t n=1): + al_(al),n_(n),data_(n_?allocator::allocate(al_,n_):0) + {} + + ~auto_space() + { + if(n_)allocator::deallocate(al_,data_,n_); + } + + T* data()const{return data_;} + +private: + typename allocator::rebind_to::type al_; + std::size_t n_; + T* data_; +}; + +} /* namespace multi_index::detail */ + +} /* namespace multi_index */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/multi_index/detail/base_type.hpp b/include/boost/multi_index/detail/base_type.hpp new file mode 100644 index 0000000..f783d48 --- /dev/null +++ b/include/boost/multi_index/detail/base_type.hpp @@ -0,0 +1,81 @@ +/* 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. + */ + +#ifndef BOOST_MULTI_INDEX_DETAIL_BASE_TYPE_HPP +#define BOOST_MULTI_INDEX_DETAIL_BASE_TYPE_HPP + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost{ + +namespace multi_index{ + +namespace detail{ + +/* MPL machinery to construct a linear hierarchy of indices out of + * a index list. + */ + +#if BOOST_WORKAROUND(BOOST_MSVC,<1300) +struct index_applier +{ + template + struct apply: + msvc_index_specifier:: + template result_index_class + { + }; +}; +#else +struct index_applier +{ + template + struct apply:IndexSpecifierIterator::type:: + BOOST_NESTED_TEMPLATE index_class + { + }; +}; +#endif + +template +struct multi_index_base_type +{ + BOOST_STATIC_ASSERT(detail::is_index_list::value); + + typedef typename prevent_eti< + multi_index_container, + typename mpl::iter_fold_backward< + IndexSpecifierList, + index_base, + mpl::bind2< + index_applier, + mpl::_2, + mpl::_1 + > + >::type + >::type type; +}; + +} /* namespace multi_index::detail */ + +} /* namespace multi_index */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/multi_index/detail/converter.hpp b/include/boost/multi_index/detail/converter.hpp new file mode 100644 index 0000000..fd3e07e --- /dev/null +++ b/include/boost/multi_index/detail/converter.hpp @@ -0,0 +1,48 @@ +/* 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. + */ + +#ifndef BOOST_MULTI_INDEX_DETAIL_CONVERTER_HPP +#define BOOST_MULTI_INDEX_DETAIL_CONVERTER_HPP + +namespace boost{ + +namespace multi_index{ + +namespace detail{ + +/* converter offers means to access indices of a given multi_index_container + * and for convertibilty between index iterators, so providing a + * localized access point for get() and project() functions. + */ + +template +struct converter +{ + static const Index& index(const MultiIndexContainer& x){return x;} + static Index& index(MultiIndexContainer& x){return x;} + + static typename Index::const_iterator const_iterator( + const MultiIndexContainer& x,typename MultiIndexContainer::node_type* node) + { + return x.Index::make_iterator(node); + } + + static typename Index::iterator iterator( + MultiIndexContainer& x,typename MultiIndexContainer::node_type* node) + { + return x.Index::make_iterator(node); + } +}; + +} /* namespace multi_index::detail */ + +} /* namespace multi_index */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/multi_index/detail/copy_map.hpp b/include/boost/multi_index/detail/copy_map.hpp new file mode 100644 index 0000000..496cc86 --- /dev/null +++ b/include/boost/multi_index/detail/copy_map.hpp @@ -0,0 +1,127 @@ +/* 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. + */ + +#ifndef BOOST_MULTI_INDEX_DETAIL_COPY_MAP_HPP +#define BOOST_MULTI_INDEX_DETAIL_COPY_MAP_HPP + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include +#include +#include +#include +#include + +namespace boost{ + +namespace multi_index{ + +namespace detail{ + +/* copy_map is used as an auxiliary structure during copy_() operations. + * When a container with n nodes is replicated, node_map holds the pairings + * between original and copied nodes, and provides a fast way to find a + * copied node from an original one. + * The semantics of the class are not simple, and no attempt has been made + * to enforce it: multi_index_container handles it right. On the other hand, + * the const interface, which is the one provided to index implementations, + * only allows for: + * - Enumeration of pairs of (original,copied) nodes (excluding the headers), + * - fast retrieval of copied nodes (including the headers.) + */ + +template +struct copy_map_entry +{ + copy_map_entry(Node* f,Node* s):first(f),second(s){} + + Node* first; + Node* second; + + bool operator<(const copy_map_entry& x)const + { + return std::less()(first,x.first); + } +}; + +template +class copy_map:private noncopyable +{ +public: + typedef const copy_map_entry* const_iterator; + + copy_map( + const Allocator al,std::size_t size,Node* header_org,Node* header_cpy): + al_(al),size_(size),spc(al_,size_),n(0), + header_org_(header_org),header_cpy_(header_cpy),released(false) + {} + + ~copy_map() + { + if(!released){ + for(std::size_t i=0;ivalue); + deallocate(spc.data()[i].second); + } + } + } + + const_iterator begin()const{return &spc.data()[0];} + const_iterator end()const{return &spc.data()[n];} + + void clone(Node* node) + { + spc.data()[n].first=node; + spc.data()[n].second=allocator::allocate(al_,1); + BOOST_TRY{ + allocator::construct(&spc.data()[n].second->value,node->value); + } + BOOST_CATCH(...){ + deallocate(spc.data()[n].second); + BOOST_RETHROW; + } + BOOST_CATCH_END + ++n; + + if(n==size_)std::sort(&spc.data()[0],&spc.data()[size_]); + } + + Node* find(Node* node)const + { + if(node==header_org_)return header_cpy_; + return std::lower_bound( + &spc.data()[0],&spc.data()[n],copy_map_entry(node,0))->second; + }; + + void release() + { + released=true; + } + +private: + typename allocator::rebind_to::type al_; + std::size_t size_; + auto_space,Allocator> spc; + std::size_t n; + Node* header_org_; + Node* header_cpy_; + bool released; + + void deallocate(Node* node) + { + allocator::deallocate(al_,node,1); + } +}; + +} /* namespace multi_index::detail */ + +} /* namespace multi_index */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/multi_index/detail/def_ctor_tuple_cons.hpp b/include/boost/multi_index/detail/def_ctor_tuple_cons.hpp new file mode 100644 index 0000000..02a8cd4 --- /dev/null +++ b/include/boost/multi_index/detail/def_ctor_tuple_cons.hpp @@ -0,0 +1,55 @@ +/* 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. + */ + +#ifndef BOOST_MULTI_INDEX_DETAIL_DEF_CTOR_TUPLE_CONS_HPP +#define BOOST_MULTI_INDEX_DETAIL_DEF_CTOR_TUPLE_CONS_HPP + +#include + +#if defined(BOOST_MSVC) +/* In MSVC, tuples::cons is not default constructible. We provide a + * tiny wrapper around tuple::cons filling that hole. + */ + +#include + +namespace boost{ + +namespace multi_index{ + +namespace detail{ + +template +struct default_constructible_tuple_cons:Cons +{ + default_constructible_tuple_cons(): + Cons( + Cons::head_type(), + static_cast( + default_constructible_tuple_cons())) + {} + + default_constructible_tuple_cons(const Cons& cons):Cons(cons){} +}; + +template<> +struct default_constructible_tuple_cons:tuples::null_type +{ + default_constructible_tuple_cons(){} + default_constructible_tuple_cons(const tuples::null_type&){} +}; + +} /* namespace multi_index::detail */ + +} /* namespace multi_index */ + +} /* namespace boost */ + +#endif /* BOOST_MSVC */ + +#endif diff --git a/include/boost/multi_index/detail/has_tag.hpp b/include/boost/multi_index/detail/has_tag.hpp new file mode 100644 index 0000000..51ad590 --- /dev/null +++ b/include/boost/multi_index/detail/has_tag.hpp @@ -0,0 +1,38 @@ +/* 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. + */ + +#ifndef BOOST_MULTI_INDEX_DETAIL_HAS_TAG_HPP +#define BOOST_MULTI_INDEX_DETAIL_HAS_TAG_HPP + +#include /* keep it first to prevent nasty warns in MSVC */ +#include + +namespace boost{ + +namespace multi_index{ + +namespace detail{ + +/* determines whether an index type has a given tag in its tag list */ + +template +struct has_tag +{ + template + struct apply:mpl::contains + { + }; +}; + +} /* namespace multi_index::detail */ + +} /* namespace multi_index */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/multi_index/detail/header_holder.hpp b/include/boost/multi_index/detail/header_holder.hpp new file mode 100644 index 0000000..ef0a9d4 --- /dev/null +++ b/include/boost/multi_index/detail/header_holder.hpp @@ -0,0 +1,49 @@ +/* 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. + */ + +#ifndef BOOST_MULTI_INDEX_DETAIL_HEADER_HOLDER_HPP +#define BOOST_MULTI_INDEX_DETAIL_HEADER_HOLDER_HPP + +#include +#include + +namespace boost{ + +namespace multi_index{ + +namespace detail{ + +/* An utility class derived from base_from_member used to hold + * a pointer to the header node. The base from member idiom is used + * because index classes, which are superclasses of multi_index_container, + * need this header in construction time. + * The allocation is made by the allocator of the multi_index_container + * class --hence, this allocator needs also be stored resorting + * to the base from member trick. + */ + +template +struct header_holder:base_from_member,private noncopyable +{ + header_holder():super(final().allocate_node()){} + ~header_holder(){final().deallocate_node(super::member);} + +private: + typedef base_from_member super; + Final& final(){return *static_cast(this);} +}; + + + +} /* namespace multi_index::detail */ + +} /* namespace multi_index */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/multi_index/detail/index_base.hpp b/include/boost/multi_index/detail/index_base.hpp new file mode 100644 index 0000000..cec41d2 --- /dev/null +++ b/include/boost/multi_index/detail/index_base.hpp @@ -0,0 +1,133 @@ +/* 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. + */ + +#ifndef BOOST_MULTI_INDEX_DETAIL_INDEX_BASE_HPP +#define BOOST_MULTI_INDEX_DETAIL_INDEX_BASE_HPP + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost{ + +namespace multi_index{ + +namespace detail{ + +/* The role of this class is threefold: + * - tops the linear hierarchy of indices. + * - terminates some cascading backbone function calls (insert_, etc.), + * - grants access to the backbone functions of the final + * multi_index_container class (for access restriction reasons, these + * cannot be called directly from the index classes.) + */ + +template +class index_base +{ +protected: + typedef index_node_base node_type; + typedef typename multi_index_node_type< + Value,IndexSpecifierList,Allocator>::type final_node_type; + typedef multi_index_container< + Value,IndexSpecifierList,Allocator> final_type; + typedef tuples::null_type ctor_args_list; + typedef Allocator final_allocator_type; + typedef mpl::vector0<> index_type_list; + typedef mpl::vector0<> iterator_type_list; + typedef mpl::vector0<> const_iterator_type_list; + typedef copy_map copy_map_type; + +private: + typedef typename call_traits::param_type value_param_type; + +protected: + explicit index_base(const ctor_args_list&,const Allocator&){} + + void copy_( + const index_base&,const copy_map_type&) + {} + + node_type* insert_(value_param_type v,node_type* x) + { + detail::allocator::construct(&x->value,v); + return x; + } + + node_type* insert_(value_param_type v,node_type*,node_type* x) + { + detail::allocator::construct(&x->value,v); + return x; + } + + void erase_(node_type* x) + { + detail::allocator::destroy(&x->value); + } + + void swap_(index_base&){} + + bool replace_(value_param_type v,node_type* x) + { + x->value=v; + return true; + } + + bool modify_(node_type*){return true;} + +#if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING) + /* invariant stuff */ + + bool invariant_()const{return true;} +#endif + + /* access to backbone memfuns of Final class */ + + final_type& final(){return *static_cast(this);} + const final_type& final()const{return *static_cast(this);} + + final_node_type* final_header()const{return final().header();} + + bool final_empty_()const{return final().empty_();} + std::size_t final_size_()const{return final().size_();} + std::size_t final_max_size_()const{return final.max_size_();} + + std::pair final_insert_(value_param_type x) + {return final().insert_(x);} + std::pair final_insert_( + value_param_type x,final_node_type* position) + {return final().insert_(x,position);} + + void final_erase_(final_node_type* x){final().erase_(x);} + void final_swap_(final_type& x){final().swap_(x);} + bool final_replace_( + value_param_type k,final_node_type* x) + {return final().replace_(k,x);} + + template + bool final_modify_(Modifier mod,final_node_type* x) + {return final().modify_(mod,x);} + +#if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING) + void final_check_invariant_()const{final().check_invariant_();} +#endif +}; + +} /* namespace multi_index::detail */ + +} /* namespace multi_index */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/multi_index/detail/index_iterator.hpp b/include/boost/multi_index/detail/index_iterator.hpp new file mode 100644 index 0000000..934624f --- /dev/null +++ b/include/boost/multi_index/detail/index_iterator.hpp @@ -0,0 +1,140 @@ +/* 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. + */ + +#ifndef BOOST_MULTI_INDEX_DETAIL_INDEX_ITERATOR_HPP +#define BOOST_MULTI_INDEX_DETAIL_INDEX_ITERATOR_HPP + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include +#include +#include +#include + +namespace boost{ + +namespace multi_index{ + +namespace detail{ + +/* An iterator template for nodes of multi_index::detail::index. + * Built with the aid boost::bidirectional_iterator_helper from + * boost/operators.hpp. + */ + +#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE) +#if BOOST_WORKAROUND(BOOST_MSVC,<1300) +template +class index_iterator: + public boost::bidirectional_iterator_helper< + index_iterator, + typename Node::value_type, + std::ptrdiff_t, + const typename Node::value_type*, + const typename Node::value_type&>, + public safe_iterator > +#else +template +class index_iterator: + public boost::bidirectional_iterator_helper< + index_iterator, + typename Node::value_type, + std::ptrdiff_t, + const typename Node::value_type*, + const typename Node::value_type&>, + public safe_iterator +#endif +#else +template +class index_iterator: + public boost::bidirectional_iterator_helper< + index_iterator, + typename Node::value_type, + std::ptrdiff_t, + const typename Node::value_type*, + const typename Node::value_type&> +#endif + +{ +#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE) +public: + +#if BOOST_WORKAROUND(BOOST_MSVC,<1300) + typedef index_proxy container_type; +#else + typedef Container container_type; +#endif + +private: + typedef safe_iterator safe_super; + +public: + index_iterator():node(0){} + index_iterator(Node* node_,container_type* cont_): + safe_super(cont_),node(node_){} + + index_iterator& operator=(const index_iterator& x) + { + safe_super::operator=(x); + node=x.node; + return *this; + } + +#else +public: + index_iterator(){} + index_iterator(Node* node_):node(node_){} +#endif + + + const typename Node::value_type& operator*()const + { + BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(*this); + BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(*this); + return node->value; + } + + index_iterator& operator++() + { + BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(*this); + BOOST_MULTI_INDEX_CHECK_INCREMENTABLE_ITERATOR(*this); + Node::increment(node); + return *this; + } + + index_iterator& operator--() + { + BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(*this); + BOOST_MULTI_INDEX_CHECK_DECREMENTABLE_ITERATOR(*this); + Node::decrement(node); + return *this; + } + + friend bool operator==(const index_iterator& x,const index_iterator& y) + { + BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(x); + BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(y); + BOOST_MULTI_INDEX_CHECK_SAME_OWNER(x,y); + return x.node==y.node; + } + + /* get_node is not to be used by the user */ + + Node* get_node()const{return node;} + +private: + Node* node; +}; + +} /* namespace multi_index::detail */ + +} /* namespace multi_index */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/multi_index/detail/index_iterator_fwd.hpp b/include/boost/multi_index/detail/index_iterator_fwd.hpp new file mode 100644 index 0000000..4c63237 --- /dev/null +++ b/include/boost/multi_index/detail/index_iterator_fwd.hpp @@ -0,0 +1,40 @@ +/* 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. + */ + +#ifndef BOOST_MULTI_INDEX_DETAIL_INDEX_ITERATOR_FWD_HPP +#define BOOST_MULTI_INDEX_DETAIL_INDEX_ITERATOR_FWD_HPP + +#include +#include + +namespace boost{ + +namespace multi_index{ + +namespace detail{ + +#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE) +#if BOOST_WORKAROUND(BOOST_MSVC,<1300) +template +class index_iterator; +#else +template +class index_iterator; +#endif +#else +template +class index_iterator; +#endif + +} /* namespace multi_index::detail */ + +} /* namespace multi_index */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/multi_index/detail/index_node_base.hpp b/include/boost/multi_index/detail/index_node_base.hpp new file mode 100644 index 0000000..c3fde3c --- /dev/null +++ b/include/boost/multi_index/detail/index_node_base.hpp @@ -0,0 +1,39 @@ +/* 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. + */ + +#ifndef BOOST_MULTI_INDEX_DETAIL_INDEX_NODE_BASE_HPP +#define BOOST_MULTI_INDEX_DETAIL_INDEX_NODE_BASE_HPP + +namespace boost{ + +namespace multi_index{ + +namespace detail{ + +/* index_node_base tops the node hierarchy of multi_index_container. It holds + * the value of the element contained. + */ + +template +struct index_node_base +{ + typedef Value value_type; + value_type value; + +private: + index_node_base(); + /* this class is not intended to be cted, merely allocated */ +}; + +} /* namespace multi_index::detail */ + +} /* namespace multi_index */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/multi_index/detail/index_proxy.hpp b/include/boost/multi_index/detail/index_proxy.hpp new file mode 100644 index 0000000..7d671dd --- /dev/null +++ b/include/boost/multi_index/detail/index_proxy.hpp @@ -0,0 +1,78 @@ +/* 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. + */ + +#ifndef BOOST_MULTI_INDEX_DETAIL_INDEX_PROXY_HPP +#define BOOST_MULTI_INDEX_DETAIL_INDEX_PROXY_HPP + +#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE) +#include /* keep it first to prevent nasty warns in MSVC */ +#include + +#if BOOST_WORKAROUND(BOOST_MSVC,<1300) +#include +#include +#include + +namespace boost{ + +namespace multi_index{ + +namespace detail{ + +/* In safe mode, index iterators are derived from safe_iterator, + * where Index is the type of the index where the iterator belongs. Due + * to the long symbol names of indices, MSVC++ 6.0 often issues a + * LNK1179 (duplicate comdat) error. To workaround this problem, + * index_proxy is used instead. index_proxy acts as an index + * over nodes of type Node in all aspects relevant to safe_iterator, and + * its shorter symbol name makes life easier for MSVC++ 6.0. + */ + +template +class index_proxy:public safe_container > +{ +protected: + index_proxy(Node* header_):header(header_){} + + void swap(index_proxy& x) + { + std::swap(header,x.header); + safe_container >::swap(x); + } + +public: + typedef index_iterator iterator; + typedef index_iterator const_iterator; + + index_iterator begin()const + { + return index_iterator( + Node::begin(header),const_cast(this)); + } + + index_iterator end()const + { + return index_iterator( + Node::end(header),const_cast(this)); + } + +private: + Node* header; +}; + +} /* namespace multi_index::detail */ + +} /* namespace multi_index */ + +} /* namespace boost */ + +#endif /* workaround */ + +#endif /* BOOST_MULTI_INDEX_ENABLE_SAFE_MODE */ + +#endif diff --git a/include/boost/multi_index/detail/invariant_assert.hpp b/include/boost/multi_index/detail/invariant_assert.hpp new file mode 100644 index 0000000..21f823a --- /dev/null +++ b/include/boost/multi_index/detail/invariant_assert.hpp @@ -0,0 +1,17 @@ +/* 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. + */ + +#ifndef BOOST_MULTI_INDEX_DETAIL_INVARIANT_ASSERT_HPP +#define BOOST_MULTI_INDEX_DETAIL_INVARIANT_ASSERT_HPP + +#if !defined(BOOST_MULTI_INDEX_INVARIANT_ASSERT) +#include +#define BOOST_MULTI_INDEX_INVARIANT_ASSERT BOOST_ASSERT +#endif + +#endif diff --git a/include/boost/multi_index/detail/is_index_list.hpp b/include/boost/multi_index/detail/is_index_list.hpp new file mode 100644 index 0000000..a5d425a --- /dev/null +++ b/include/boost/multi_index/detail/is_index_list.hpp @@ -0,0 +1,36 @@ +/* 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. + */ + +#ifndef BOOST_MULTI_INDEX_DETAIL_IS_INDEX_LIST_HPP +#define BOOST_MULTI_INDEX_DETAIL_IS_INDEX_LIST_HPP + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include + +namespace boost{ + +namespace multi_index{ + +namespace detail{ + +template +struct is_index_list +{ + BOOST_STATIC_CONSTANT(bool,mpl_sequence=mpl::is_sequence::value); + BOOST_STATIC_CONSTANT(bool,non_empty=!mpl::empty::value); + BOOST_STATIC_CONSTANT(bool,value=mpl_sequence&&non_empty); +}; + +} /* namespace multi_index::detail */ + +} /* namespace multi_index */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/multi_index/detail/modify_key_adaptor.hpp b/include/boost/multi_index/detail/modify_key_adaptor.hpp new file mode 100644 index 0000000..bb048e6 --- /dev/null +++ b/include/boost/multi_index/detail/modify_key_adaptor.hpp @@ -0,0 +1,45 @@ +/* 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. + */ + +#ifndef BOOST_MULTI_INDEX_DETAIL_MODIFY_KEY_ADAPTOR_HPP +#define BOOST_MULTI_INDEX_DETAIL_MODIFY_KEY_ADAPTOR_HPP + +namespace boost{ + +namespace multi_index{ + +namespace detail{ + +/* Functional adaptor to resolve modify_key as a call to modify. + * Preferred over compose_f_gx and stuff cause it eliminates problems + * with references to references, dealing with function pointers, etc. + */ + +template +struct modify_key_adaptor +{ + + modify_key_adaptor(Modifier mod_,KeyFromValue kfv_):mod(mod_),kfv(kfv_){} + + void operator()(Value& x) + { + mod(kfv(x)); + } + +private: + Modifier mod; + KeyFromValue kfv; +}; + +} /* namespace multi_index::detail */ + +} /* namespace multi_index */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/multi_index/detail/msvc_index_specifier.hpp b/include/boost/multi_index/detail/msvc_index_specifier.hpp new file mode 100644 index 0000000..225743e --- /dev/null +++ b/include/boost/multi_index/detail/msvc_index_specifier.hpp @@ -0,0 +1,65 @@ +/* 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. + */ + +#ifndef BOOST_MULTI_INDEX_DETAIL_MSVC_INDEX_SPECIFIER_HPP +#define BOOST_MULTI_INDEX_DETAIL_MSVC_INDEX_SPECIFIER_HPP + +#include /* keep it first to prevent nasty warns in MSVC */ +#include + +#if BOOST_WORKAROUND(BOOST_MSVC,<1300) +/* Workaround for a problem in MSVC with dependent template typedefs + * when accesing index specifiers. + * Modeled after (thanks, Aleksey!) + */ + +#include + +namespace boost{ + +namespace multi_index{ + +namespace detail{ + +template +struct msvc_index_specifier +{ + template struct fake_index_type:IndexSpecifier{}; + template<> struct fake_index_type + { + template + struct node_class{}; + + template + struct index_class{}; + }; + + template + struct result_node_class: + fake_index_type::value>:: + template node_class + { + }; + + template + struct result_index_class: + fake_index_type::value>:: + template index_class + { + }; +}; + +} /* namespace multi_index::detail */ + +} /* namespace multi_index */ + +} /* namespace boost */ + +#endif /* workaround */ + +#endif diff --git a/include/boost/multi_index/detail/no_duplicate_tags.hpp b/include/boost/multi_index/detail/no_duplicate_tags.hpp new file mode 100644 index 0000000..4966450 --- /dev/null +++ b/include/boost/multi_index/detail/no_duplicate_tags.hpp @@ -0,0 +1,93 @@ +/* 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. + */ + +#ifndef BOOST_MULTI_INDEX_DETAIL_NO_DUPLICATE_TAGS_HPP +#define BOOST_MULTI_INDEX_DETAIL_NO_DUPLICATE_TAGS_HPP + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include + +namespace boost{ + +namespace multi_index{ + +namespace detail{ + +/* no_duplicate_tags check at compile-time that a tag list + * has no duplicate tags. + * The algorithm deserves some explanation: tags + * are sequentially inserted into a mpl::set if they were + * not already present. Due to the magic of mpl::set + * (mpl::has_key is contant time), this operation takes linear + * time, and even MSVC++ 6.5 handles it gracefully (other obvious + * solutions are quadratic.) + */ + +struct duplicate_tag_mark{}; + +struct duplicate_tag_marker +{ + template + struct apply + { + typedef mpl::s_item< + typename mpl::if_,duplicate_tag_mark,Tag>::type, + MplSet + > type; + }; +}; + +template +struct no_duplicate_tags +{ + typedef typename mpl::fold< + TagList, + mpl::set0<>, + duplicate_tag_marker + >::type aux; + + BOOST_STATIC_CONSTANT( + bool,value=!(mpl::has_key::value)); +}; + +/* Variant for an index list: duplication is checked + * across all the indices. + */ + +struct duplicate_tag_list_marker +{ + template + struct apply:mpl::fold< + BOOST_DEDUCED_TYPENAME Index::tag_list, + MplSet, + duplicate_tag_marker> + { + }; +}; + +template +struct no_duplicate_tags_in_index_list +{ + typedef typename mpl::fold< + IndexList, + mpl::set0<>, + duplicate_tag_list_marker + >::type aux; + + BOOST_STATIC_CONSTANT( + bool,value=!(mpl::has_key::value)); +}; + +} /* namespace multi_index::detail */ + +} /* namespace multi_index */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/multi_index/detail/node_type.hpp b/include/boost/multi_index/detail/node_type.hpp new file mode 100644 index 0000000..1f63f76 --- /dev/null +++ b/include/boost/multi_index/detail/node_type.hpp @@ -0,0 +1,73 @@ +/* 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. + */ + +#ifndef BOOST_MULTI_INDEX_DETAIL_NODE_TYPE_HPP +#define BOOST_MULTI_INDEX_DETAIL_NODE_TYPE_HPP + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost{ + +namespace multi_index{ + +namespace detail{ + +/* MPL machinery to construct the internal node type associated to an + * index list. + */ + +#if BOOST_WORKAROUND(BOOST_MSVC,<1300) +struct index_node_applier +{ + template + struct apply: + msvc_index_specifier:: + template result_node_class + { + }; +}; +#else +struct index_node_applier +{ + template + struct apply:IndexSpecifierIterator::type:: + BOOST_NESTED_TEMPLATE node_class + { + }; +}; +#endif + +template +struct multi_index_node_type +{ + BOOST_STATIC_ASSERT(detail::is_index_list::value); + + typedef typename mpl::iter_fold_backward< + IndexSpecifierList, + index_node_base, + mpl::bind2 + >::type type; +}; + +} /* namespace multi_index::detail */ + +} /* namespace multi_index */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/multi_index/detail/ord_index_args.hpp b/include/boost/multi_index/detail/ord_index_args.hpp new file mode 100644 index 0000000..34ecc9e --- /dev/null +++ b/include/boost/multi_index/detail/ord_index_args.hpp @@ -0,0 +1,86 @@ +/* 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. + */ + +#ifndef BOOST_MULTI_INDEX_DETAIL_ORD_INDEX_ARGS_HPP +#define BOOST_MULTI_INDEX_DETAIL_ORD_INDEX_ARGS_HPP + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include +#include +#include +#include +#include +#include + +namespace boost{ + +namespace multi_index{ + +namespace detail{ + +/* Oredered index specifiers can be instantiated in two forms: + * + * (ordered_unique|ordered_non_unique)< + * KeyFromValue,Compare=std::less > + * (ordered_unique|ordered_non_unique)< + * TagList,KeyFromValue,Compare=std::less > + * + * index_args implements the machinery to accept this argument-dependent + * polymorphism. + */ + +struct null_arg{}; + +template +struct not_is_null_arg +{ + BOOST_STATIC_CONSTANT(bool,value=!(is_same::value)); +}; + +template +struct index_args_default_compare +{ + typedef std::less type; +}; + +template +struct ordered_index_args +{ + typedef is_tag full_form; + + typedef typename mpl::if_< + full_form, + Arg1, + tag< > >::type tag_list_type; + typedef typename mpl::if_< + full_form, + Arg2, + Arg1>::type key_from_value_type; + typedef typename mpl::if_< + full_form, + Arg3, + Arg2>::type supplied_compare_type; + typedef typename mpl::apply_if< + is_same, + index_args_default_compare, + mpl::identity + >::type compare_type; + + BOOST_STATIC_ASSERT(is_tag::value); + BOOST_STATIC_ASSERT(not_is_null_arg::value); + BOOST_STATIC_ASSERT(not_is_null_arg::value); +}; + +} /* namespace multi_index::detail */ + +} /* namespace multi_index */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/multi_index/detail/ord_index_node.hpp b/include/boost/multi_index/detail/ord_index_node.hpp new file mode 100644 index 0000000..12ad422 --- /dev/null +++ b/include/boost/multi_index/detail/ord_index_node.hpp @@ -0,0 +1,457 @@ +/* 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. + * + * The internal implementation of red-black trees is based on that of SGI STL + * stl_tree.h file: + * + * 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. + * + */ + +#ifndef BOOST_MULTI_INDEX_DETAIL_ORD_INDEX_NODE_HPP +#define BOOST_MULTI_INDEX_DETAIL_ORD_INDEX_NODE_HPP + +#include +#include + +namespace boost{ + +namespace multi_index{ + +namespace detail{ + +/* definition of red-black nodes for ordered_index */ + +enum ordered_index_color{red=false,black=true}; + +struct ordered_index_node_impl +{ + ordered_index_color& color(){return color_;} + const ordered_index_color& color()const{return color_;} + ordered_index_node_impl*& parent(){return parent_;} + ordered_index_node_impl*const & parent()const{return parent_;} + ordered_index_node_impl*& left(){return left_;} + ordered_index_node_impl*const & left()const{return left_;} + ordered_index_node_impl*& right(){return right_;} + ordered_index_node_impl*const & right()const{return right_;} + + /* interoperability with index_iterator */ + + static void increment(ordered_index_node_impl*& x) + { + if(x->right()){ + x=x->right(); + while(x->left())x=x->left(); + } + else{ + ordered_index_node_impl* y=x->parent(); + while(x==y->right()){ + x=y; + y=y->parent(); + } + if(x->right()!=y)x=y; + } + } + + static void decrement(ordered_index_node_impl*& x) + { + if(x->color()==red&&x->parent()->parent()==x){ + x=x->right(); + } + else if(x->left()){ + ordered_index_node_impl* y=x->left(); + while(y->right())y=y->right(); + x=y; + }else{ + ordered_index_node_impl* y=x->parent(); + while(x==y->left()){ + x=y; + y=y->parent(); + } + x=y; + } + } + + /* interoperability with index_proxy */ + + static ordered_index_node_impl* begin(ordered_index_node_impl* header) + { + return header->left(); + } + + static ordered_index_node_impl* end(ordered_index_node_impl* header) + { + return header; + } + + /* algorithmic stuff */ + + static void rotate_left( + ordered_index_node_impl* x,ordered_index_node_impl*& root) + { + ordered_index_node_impl* y=x->right(); + x->right()=y->left(); + if(y->left())y->left()->parent()=x; + y->parent()=x->parent(); + + if(x==root) root=y; + else if(x==x->parent()->left())x->parent()->left()=y; + else x->parent()->right()=y; + y->left()=x; + x->parent()=y; + } + + static ordered_index_node_impl* minimum(ordered_index_node_impl* x) + { + while(x->left())x=x->left(); + return x; + } + + static ordered_index_node_impl* maximum(ordered_index_node_impl* x) + { + while(x->right())x=x->right(); + return x; + } + + static void rotate_right( + ordered_index_node_impl* x,ordered_index_node_impl*& root) + { + ordered_index_node_impl* y=x->left(); + x->left()=y->right(); + if(y->right())y->right()->parent()=x; + y->parent()=x->parent(); + + if(x==root) root=y; + else if(x==x->parent()->right())x->parent()->right()=y; + else x->parent()->left()=y; + y->right()=x; + x->parent()=y; + } + + static void rebalance( + ordered_index_node_impl* x,ordered_index_node_impl*& root) + { + x->color()=red; + while(x!=root&&x->parent()->color()==red){ + if(x->parent()==x->parent()->parent()->left()){ + ordered_index_node_impl* y=x->parent()->parent()->right(); + if(y&&y->color()==red){ + x->parent()->color()=black; + y->color()=black; + x->parent()->parent()->color()=red; + x=x->parent()->parent(); + } + else{ + if(x==x->parent()->right()){ + x=x->parent(); + rotate_left(x,root); + } + x->parent()->color()=black; + x->parent()->parent()->color()=red; + rotate_right(x->parent()->parent(),root); + } + } + else{ + ordered_index_node_impl* y=x->parent()->parent()->left(); + if(y&&y->color()==red){ + x->parent()->color()=black; + y->color()=black; + x->parent()->parent()->color()=red; + x=x->parent()->parent(); + } + else{ + if(x==x->parent()->left()){ + x=x->parent(); + rotate_right(x,root); + } + x->parent()->color()=black; + x->parent()->parent()->color()=red; + rotate_left(x->parent()->parent(),root); + } + } + } + root->color()=black; + } + + static ordered_index_node_impl* rebalance_for_erase( + ordered_index_node_impl* z,ordered_index_node_impl*& root, + ordered_index_node_impl*& leftmost,ordered_index_node_impl*& rightmost) + { + ordered_index_node_impl* y=z; + ordered_index_node_impl* x=0; + ordered_index_node_impl* x_parent=0; + if(y->left()==0){ /* z has at most one non-null child. y==z. */ + x=y->right(); /* x might be null */ + } + else{ + if(y->right()==0) { /* z has exactly one non-null child. y==z. */ + x=y->left(); /* x is not null */ + } + else{ /* z has two non-null children. Set y to */ + y=y->right(); /* z's successor. x might be null. */ + while(y->left())y=y->left(); + x=y->right(); + } + } + if(y!=z){ + z->left()->parent()=y; /* relink y in place of z. y is z's successor */ + y->left()=z->left(); + if(y!=z->right()){ + x_parent=y->parent(); + if(x) x->parent()=y->parent(); + y->parent()->left()=x; /* y must be a child of left */ + y->right()=z->right(); + z->right()->parent()=y; + } + else{ + x_parent=y; + } + + if(root==z) root=y; + else if(z->parent()->left()==z)z->parent()->left()=y; + else z->parent()->right()=y; + y->parent()=z->parent(); + std::swap(y->color(),z->color()); + y=z; /* y now points to node to be actually deleted */ + } + else{ /* y==z */ + x_parent=y->parent(); + if(x)x->parent()=y->parent(); + if(root==z){ + root=x; + } + else{ + if(z->parent()->left()==z)z->parent()->left()=x; + else z->parent()->right()=x; + } + if(leftmost==z){ + if(z->right()==0){ /* z->left() must be null also */ + leftmost=z->parent(); + } + else{ + leftmost=minimum(x); /* makes leftmost==header if z==root */ + } + } + if(rightmost==z){ + if(z->left()==0){ /* z->right() must be null also */ + rightmost=z->parent(); + } + else{ /* x==z->left() */ + rightmost=maximum(x); /* makes rightmost==header if z==root */ + } + } + } + if(y->color()!=red){ + while(x!=root&&(x==0 || x->color()==black)){ + if(x==x_parent->left()){ + ordered_index_node_impl* w=x_parent->right(); + if(w->color()==red){ + w->color()=black; + x_parent->color()=red; + rotate_left(x_parent,root); + w=x_parent->right(); + } + if((w->left()==0||w->left()->color()==black) && + (w->right()==0||w->right()->color()==black)){ + w->color()=red; + x=x_parent; + x_parent=x_parent->parent(); + } + else{ + if(w->right()==0 + || w->right()->color()==black){ + if(w->left()) w->left()->color()=black; + w->color()=red; + rotate_right(w,root); + w=x_parent->right(); + } + w->color()=x_parent->color(); + x_parent->color()=black; + if(w->right())w->right()->color()=black; + rotate_left(x_parent,root); + break; + } + } + else{ /* same as above,with right <-> left */ + ordered_index_node_impl* w=x_parent->left(); + if(w->color()==red){ + w->color()=black; + x_parent->color()=red; + rotate_right(x_parent,root); + w=x_parent->left(); + } + if((w->right()==0||w->right()->color()==black) && + (w->left()==0||w->left()->color()==black)){ + w->color()=red; + x=x_parent; + x_parent=x_parent->parent(); + } + else{ + if(w->left()==0||w->left()->color()==black){ + if(w->right())w->right()->color()=black; + w->color()=red; + rotate_left(w,root); + w=x_parent->left(); + } + w->color()=x_parent->color(); + x_parent->color()=black; + if(w->left())w->left()->color()=black; + rotate_right(x_parent,root); + break; + } + } + } + if(x)x->color()=black; + } + return y; + } + + static void restore( + ordered_index_node_impl* x,ordered_index_node_impl* prior, + ordered_index_node_impl* next,ordered_index_node_impl* header) + { + if(next==header){ + header->parent()=x; + header->left()=x; + header->right()=x; + x->parent()=header; + } + else if(next->left()==0){ + next->left()=x; + x->parent()=next; + if(next==header->left()){ + header->left()=x; /* maintain leftmost pointing to min node */ + } + } + else{ /* prior->right() must be null */ + prior->right()=x; + x->parent()=prior; + if(prior==header->right()){ + header->right()=x; /* maintain rightmost pointing to max node */ + } + } + x->left()=0; + x->right()=0; + rebalance(x,header->parent()); + } + +#if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING) + /* invariant stuff */ + + static std::size_t black_count( + ordered_index_node_impl* node,ordered_index_node_impl* root) + { + if(!node)return 0; + std::size_t sum=0; + for(;;){ + if(node->color()==black)++sum; + if(node==root)break; + node=node->parent(); + } + return sum; + } +#endif + +private: + ordered_index_node_impl(); + + ordered_index_color color_; + ordered_index_node_impl* parent_; + ordered_index_node_impl* left_; + ordered_index_node_impl* right_; +}; + +template +struct ordered_index_node_trampoline:ordered_index_node_impl{}; + +template +struct ordered_index_node:Super,ordered_index_node_trampoline +{ + ordered_index_color& color(){return impl_type::color();} + const ordered_index_color& color()const{return impl_type::color();} + ordered_index_node_impl*& parent(){return impl_type::parent();} + ordered_index_node_impl*const & parent()const{return impl_type::parent();} + ordered_index_node_impl*& left(){return impl_type::left();} + ordered_index_node_impl*const & left()const{return impl_type::left();} + ordered_index_node_impl*& right(){return impl_type::right();} + ordered_index_node_impl*const & right()const{return impl_type::right();} + + ordered_index_node_impl* impl(){return static_cast(this);} + const ordered_index_node_impl* impl()const + {return static_cast(this);} + + static ordered_index_node* from_impl(ordered_index_node_impl *x) + { + return static_cast(static_cast(x)); + } + + static const ordered_index_node* from_impl(const ordered_index_node_impl* x) + { + return static_cast( + static_cast(x)); + } + + /* interoperability with index_iterator */ + + static void increment(ordered_index_node*& x) + { + ordered_index_node_impl* xi=x->impl(); + impl_type::increment(xi); + x=from_impl(xi); + } + + static void decrement(ordered_index_node*& x) + { + ordered_index_node_impl* xi=x->impl(); + impl_type::decrement(xi); + x=from_impl(xi); + } + + /* interoperability with index_proxy */ + + static ordered_index_node* begin(ordered_index_node* header) + { + return from_impl(impl_type::begin(header->impl())); + } + + static ordered_index_node* end(ordered_index_node* header) + { + return from_impl(impl_type::end(header->impl())); + } + +private: + typedef ordered_index_node_trampoline impl_type; +}; + +} /* namespace multi_index::detail */ + +} /* namespace multi_index */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/multi_index/detail/ord_index_ops.hpp b/include/boost/multi_index/detail/ord_index_ops.hpp new file mode 100644 index 0000000..be16abb --- /dev/null +++ b/include/boost/multi_index/detail/ord_index_ops.hpp @@ -0,0 +1,121 @@ +/* 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. + * + * The internal implementation of red-black trees is based on that of SGI STL + * stl_tree.h file: + * + * 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. + * + */ + +#ifndef BOOST_MULTI_INDEX_DETAIL_ORD_INDEX_OPS_HPP +#define BOOST_MULTI_INDEX_DETAIL_ORD_INDEX_OPS_HPP + +namespace boost{ + +namespace multi_index{ + +namespace detail{ + +/* Common code for index memfuns having templatized and + * non-templatized versions. + */ + +template< + typename Node,typename KeyFromValue, + typename CompatibleKey,typename CompatibleCompare +> +inline Node* ordered_index_find( + Node* header,const KeyFromValue& key,const CompatibleKey& x, + const CompatibleCompare& comp) +{ + Node* y=header; + Node* z=Node::from_impl(header->parent()); + + while (z){ + if(!comp(key(z->value),x)){ + y=z; + z=Node::from_impl(z->left()); + } + else z=Node::from_impl(z->right()); + } + + return (y==header||comp(x,key(y->value)))?header:y; +} + +template< + typename Node,typename KeyFromValue, + typename CompatibleKey,typename CompatibleCompare +> +inline Node* ordered_index_lower_bound( + Node* header,const KeyFromValue& key,const CompatibleKey& x, + const CompatibleCompare& comp) +{ + Node* y=header; + Node* z=Node::from_impl(header->parent()); + + while(z){ + if(!comp(key(z->value),x)){ + y=z; + z=Node::from_impl(z->left()); + } + else z=Node::from_impl(z->right()); + } + + return y; +} + +template< + typename Node,typename KeyFromValue, + typename CompatibleKey,typename CompatibleCompare +> +inline Node* ordered_index_upper_bound( + Node* header,const KeyFromValue& key,const CompatibleKey& x, + const CompatibleCompare& comp) +{ + Node* y=header; + Node* z=Node::from_impl(header->parent()); + + while(z){ + if(comp(x,key(z->value))){ + y=z; + z=Node::from_impl(z->left()); + } + else z=Node::from_impl(z->right()); + } + + return y; +} + +} /* namespace multi_index::detail */ + +} /* namespace multi_index */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/multi_index/detail/prevent_eti.hpp b/include/boost/multi_index/detail/prevent_eti.hpp new file mode 100644 index 0000000..b79ad3d --- /dev/null +++ b/include/boost/multi_index/detail/prevent_eti.hpp @@ -0,0 +1,56 @@ +/* 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. + */ + +#ifndef BOOST_MULTI_INDEX_DETAIL_PREVENT_ETI_HPP +#define BOOST_MULTI_INDEX_DETAIL_PREVENT_ETI_HPP + +#include /* keep it first to prevent nasty warns in MSVC */ +#include + +#if BOOST_WORKAROUND(BOOST_MSVC,<1300) +#include +#include +#include +#endif + +namespace boost{ + +namespace multi_index{ + +namespace detail{ + +#if BOOST_WORKAROUND(BOOST_MSVC,<1300) +/* See + * http://www.crystalclearsoftware.com/cgi-bin/boost_wiki/wiki.pl?Effective_MPL + * Item 5.6, Beware of the 'early template instantiation' trap. + */ + +template +struct prevent_eti +{ + typedef typename mpl::if_< + mpl::aux::msvc_never_true, + mpl::integral_c, + Construct + >::type type; +}; +#else +template +struct prevent_eti +{ + typedef Construct type; +}; +#endif + +} /* namespace multi_index::detail */ + +} /* namespace multi_index */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/multi_index/detail/safe_mode.hpp b/include/boost/multi_index/detail/safe_mode.hpp new file mode 100644 index 0000000..33e436e --- /dev/null +++ b/include/boost/multi_index/detail/safe_mode.hpp @@ -0,0 +1,339 @@ +/* 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. + */ + +#ifndef BOOST_MULTI_INDEX_DETAIL_SAFE_MODE_HPP +#define BOOST_MULTI_INDEX_DETAIL_SAFE_MODE_HPP + +#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE) +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include +#include +#include + +namespace boost{ + +namespace multi_index{ + +/* Safe mode machinery, in the spirit of Cay Hortmann's "Safe STL" + * (http://www.horstmann.com/safestl.html). + * In this mode, containers of type Container are derived from + * safe_container, and their corresponding iterators + * are derived from safe_iterator. These classes provide + * an internal record of which iterators are at a given moment associated + * to a given container, and properly mark the iterators as invalid + * when the container gets destroyed. + * Iterators are chained in a single attached list, whose header is + * kept by the container. More elaborate data structures would yield better + * performance, but I decided to keep complexity to a minimum since + * speed is not an issue here. + * This is not a full-fledged safe mode framework, and is only inteded + * for use within the limits of Boost.MultiIndex. + */ + +namespace safe_mode{ + +/* Invalidates all iterators equivalent to that given. Defined before + * safe_iterator_base and safe_container_base as these contain friendship + * declarations to this function. + */ + +template +inline void detach_equivalent_iterators(Iterator& it) +{ + if(it.valid()){ + Iterator *prev_,*next_; + for( + prev_=static_cast(&it.cont->header); + (next_=static_cast(prev_->next))!=0;){ + if(next_!=&it&&*next_==it){ + prev_->next=next_->next; + next_->cont=0; + } + else prev_=next_; + } + it.detach(); + } +} + +} /* namespace multi_index::safe_mode */ + +namespace detail{ + +class safe_container_base; + +class safe_iterator_base +{ +public: + bool valid()const{return cont!=0;} + inline void detach(); + +protected: + safe_iterator_base():cont(0),next(0){} + explicit safe_iterator_base(safe_container_base* cont_){attach(cont_);} + safe_iterator_base(const safe_iterator_base& it){attach(it.cont);} + + safe_iterator_base& operator=(const safe_iterator_base& it) + { + safe_container_base* new_cont=it.cont; + if(cont!=new_cont){ + detach(); + attach(new_cont); + } + return *this; + } + + ~safe_iterator_base() + { + detach(); + } + + const safe_container_base* owner()const{return cont;} + +BOOST_MULTI_INDEX_PRIVATE_IF_MEMBER_TEMPLATE_FRIENDS: + friend class safe_container_base; + +#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) + template friend + void safe_mode::detach_equivalent_iterators(Iterator&); +#endif + + inline void attach(safe_container_base* cont_); + + safe_container_base* cont; + safe_iterator_base* next; +}; + +class safe_container_base:private noncopyable +{ +public: + safe_container_base(){} + + ~safe_container_base() + { + for(safe_iterator_base* it=header.next;it;it=it->next)it->cont=0; + } + + void swap(safe_container_base& x) + { + for(safe_iterator_base* it0=header.next;it0;it0=it0->next)it0->cont=&x; + for(safe_iterator_base* it1=x.header.next;it1;it1=it1->next)it1->cont=this; + std::swap(header.cont,x.header.cont); + std::swap(header.next,x.header.next); + } + +BOOST_MULTI_INDEX_PRIVATE_IF_MEMBER_TEMPLATE_FRIENDS: + friend class safe_iterator_base; + +#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) + template friend + void safe_mode::detach_equivalent_iterators(Iterator&); +#endif + + safe_iterator_base header; +}; + +void safe_iterator_base::attach(safe_container_base* cont_) +{ + cont=cont_; + if(cont){ + next=cont->header.next; + cont->header.next=this; + } +} + +void safe_iterator_base::detach() +{ + if(cont){ + safe_iterator_base *prev_,*next_; + for(prev_=&cont->header;(next_=prev_->next)!=this;prev_=next_){} + prev_->next=next; + cont=0; + } +} + +template +class safe_container; + +template +class safe_iterator:public safe_iterator_base +{ +public: + typedef Container container_type; + + safe_iterator():safe_iterator_base(){} + explicit safe_iterator(safe_container* cont_): + safe_iterator_base(cont_){} + + const container_type* owner()const + { + return + static_cast( + static_cast*>( + safe_iterator_base::owner())); + } +}; + +template +class safe_container:public safe_container_base +{ +public: + void swap(safe_container& x){safe_container_base::swap(x);} +}; + +} /* namespace multi_index::detail */ + +namespace safe_mode{ + +/* checking routines */ + +template +inline bool check_valid_iterator(const Iterator& it) +{ + return it.valid(); +} + +template +inline bool check_dereferenceable_iterator(const Iterator& it) +{ + return it.valid()&&it!=it.owner()->end(); +} + +template +inline bool check_incrementable_iterator(const Iterator& it) +{ + return it.valid()&&it!=it.owner()->end(); +} + +template +inline bool check_decrementable_iterator(const Iterator& it) +{ + return it.valid()&&it!=it.owner()->begin(); +} + +template +inline bool check_is_owner( + const Iterator& it,const typename Iterator::container_type& cont) +{ + return it.valid()&&it.owner()==&cont; +} + +template +inline bool check_same_owner(const Iterator& it0,const Iterator& it1) +{ + return it0.valid()&&it1.valid()&&it0.owner()==it1.owner(); +} + +template +inline bool check_valid_range(const Iterator& it0,const Iterator& it1) +{ + if(!it0.valid()||!it1.valid()||it0.owner()!=it1.owner())return false; + + Iterator last=it0.owner()->end(); + if(it1==last)return true; + + for(Iterator first=it0;first!=last;++first){ + if(first==it1)return true; + } + return false; +} + +template +inline bool check_outside_range( + const Iterator& it,const Iterator& it0,const Iterator& it1) +{ + if(!it0.valid()||!it1.valid()||it0.owner()!=it1.owner())return false; + + Iterator last=it0.owner()->end(); + bool found=false; + + Iterator first=it0; + for(;first!=last;++first){ + if(first==it1)break; + + /* crucial that this check goes after previous break */ + + if(first==it)found=true; + } + if(first!=it1)return false; + return !found; +} + +template +inline bool check_different_container( + const Container& cont0,const Container& cont1) +{ + return &cont0!=&cont1; +} + +} /* namespace multi_index::safe_mode */ + +} /* namespace multi_index */ + +} /* namespace boost */ + +#endif /* BOOST_MULTI_INDEX_ENABLE_SAFE_MODE */ + +/* assertion macros */ + +#if !defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE) +#undef BOOST_MULTI_INDEX_SAFE_MODE_ASSERT +#define BOOST_MULTI_INDEX_SAFE_MODE_ASSERT(expr,error_code) ((void)0) +#else +#if !defined(BOOST_MULTI_INDEX_SAFE_MODE_ASSERT) +#include +#define BOOST_MULTI_INDEX_SAFE_MODE_ASSERT(expr,error_code) BOOST_ASSERT(expr) +#endif +#endif + +#define BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(it) \ + BOOST_MULTI_INDEX_SAFE_MODE_ASSERT( \ + safe_mode::check_valid_iterator(it), \ + safe_mode::invalid_iterator); + +#define BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(it) \ + BOOST_MULTI_INDEX_SAFE_MODE_ASSERT( \ + safe_mode::check_dereferenceable_iterator(it), \ + safe_mode::not_dereferenceable_iterator); + +#define BOOST_MULTI_INDEX_CHECK_INCREMENTABLE_ITERATOR(it) \ + BOOST_MULTI_INDEX_SAFE_MODE_ASSERT( \ + safe_mode::check_incrementable_iterator(it), \ + safe_mode::not_incrementable_iterator); + +#define BOOST_MULTI_INDEX_CHECK_DECREMENTABLE_ITERATOR(it) \ + BOOST_MULTI_INDEX_SAFE_MODE_ASSERT(\ + safe_mode::check_decrementable_iterator(it), \ + safe_mode::not_decrementable_iterator); + +#define BOOST_MULTI_INDEX_CHECK_IS_OWNER(it,cont) \ + BOOST_MULTI_INDEX_SAFE_MODE_ASSERT( \ + safe_mode::check_is_owner(it,cont), \ + safe_mode::not_owner); + +#define BOOST_MULTI_INDEX_CHECK_SAME_OWNER(it0,it1) \ + BOOST_MULTI_INDEX_SAFE_MODE_ASSERT(\ + safe_mode::check_same_owner(it0,it1), \ + safe_mode::not_same_owner); + +#define BOOST_MULTI_INDEX_CHECK_VALID_RANGE(it0,it1) \ + BOOST_MULTI_INDEX_SAFE_MODE_ASSERT( \ + safe_mode::check_valid_range(it0,it1), \ + safe_mode::invalid_range); + +#define BOOST_MULTI_INDEX_CHECK_OUTSIDE_RANGE(it,it0,it1) \ + BOOST_MULTI_INDEX_SAFE_MODE_ASSERT(\ + safe_mode::check_outside_range(it,it0,it1), \ + safe_mode::inside_range); + +#define BOOST_MULTI_INDEX_CHECK_DIFFERENT_CONTAINER(cont0,cont1) \ + BOOST_MULTI_INDEX_SAFE_MODE_ASSERT( \ + safe_mode::check_different_container(cont0,cont1), \ + safe_mode::same_container); + +#endif diff --git a/include/boost/multi_index/detail/scope_guard.hpp b/include/boost/multi_index/detail/scope_guard.hpp new file mode 100644 index 0000000..8481d07 --- /dev/null +++ b/include/boost/multi_index/detail/scope_guard.hpp @@ -0,0 +1,270 @@ +/* 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. + */ + +#ifndef BOOST_MULTI_INDEX_DETAIL_SCOPE_GUARD_HPP +#define BOOST_MULTI_INDEX_DETAIL_SCOPE_GUARD_HPP + +namespace boost{ + +namespace multi_index{ + +namespace detail{ + +/* Until some official version of the ScopeGuard idiom makes it into Boost, + * we locally define our own. This is a merely reformated version of + * ScopeGuard.h as defined in: + * Alexandrescu, A., Marginean, P.:"Generic: Change the Way You + * Write Exception-Safe Code - Forever", C/C++ Users Jornal, Dec 2000, + * http://www.cuj.com/documents/s=8000/cujcexp1812alexandr/ + * with the following modifications: + * - General pretty formatting (pretty to my taste at least.) + * - Naming style changed to standard C++ library requirements. + * - safe_execute does not feature a try-catch protection, so we can + * use this even if BOOST_NO_EXCEPTIONS is defined. + * - Added scope_guard_impl4 and obj_scope_guard_impl3, (Boost.MultiIndex + * needs them). A better design would provide guards for many more + * arguments through the Boost Preprocessor Library. + * - Added scope_guard_impl_base::touch (see below.) + * - Removed RefHolder and ByRef, whose functionality is provided + * already by Boost.Ref. + * - Removed static make_guard's and make_obj_guard's, so that the code + * will work even if BOOST_NO_MEMBER_TEMPLATES is defined. This forces + * us to move some private ctors to public, though. + */ + +class scope_guard_impl_base +{ +public: + scope_guard_impl_base():dismissed_(false){} + void dismiss()const{dismissed_=true;} + + /* This helps prevent some "unused variable" warnings under, for instance, + * GCC 3.2. + */ + void touch()const{} + +protected: + ~scope_guard_impl_base(){} + + scope_guard_impl_base(const scope_guard_impl_base& other): + dismissed_(other.dismissed_) + { + other.dismiss(); + } + + template + static void safe_execute(J& j){if(!j.dismissed_)j.execute();} + + mutable bool dismissed_; + +private: + scope_guard_impl_base& operator=(const scope_guard_impl_base&); +}; + +typedef const scope_guard_impl_base& scope_guard; + +template +class scope_guard_impl0:public scope_guard_impl_base +{ +public: + scope_guard_impl0(F fun):fun_(fun){} + ~scope_guard_impl0(){safe_execute(*this);} + void execute(){fun_();} + +protected: + + F fun_; +}; + +template +inline scope_guard_impl0 make_guard(F fun) +{ + return scope_guard_impl0(fun); +} + +template +class scope_guard_impl1:public scope_guard_impl_base +{ +public: + scope_guard_impl1(F fun,P1 p1):fun_(fun),p1_(p1){} + ~scope_guard_impl1(){safe_execute(*this);} + void execute(){fun_(p1_);} + +protected: + F fun_; + const P1 p1_; +}; + +template +inline scope_guard_impl1 make_guard(F fun,P1 p1) +{ + return scope_guard_impl1(fun,p1); +} + +template +class scope_guard_impl2:public scope_guard_impl_base +{ +public: + scope_guard_impl2(F fun,P1 p1,P2 p2):fun_(fun),p1_(p1),p2_(p2){} + ~scope_guard_impl2(){safe_execute(*this);} + void execute(){fun_(p1_,p2_);} + +protected: + F fun_; + const P1 p1_; + const P2 p2_; +}; + +template +inline scope_guard_impl2 make_guard(F fun,P1 p1,P2 p2) +{ + return scope_guard_impl2(fun,p1,p2); +} + +template +class scope_guard_impl3:public scope_guard_impl_base +{ +public: + scope_guard_impl3(F fun,P1 p1,P2 p2,P3 p3):fun_(fun),p1_(p1),p2_(p2),p3_(p3){} + ~scope_guard_impl3(){safe_execute(*this);} + void execute(){fun_(p1_,p2_,p3_);} + +protected: + F fun_; + const P1 p1_; + const P2 p2_; + const P3 p3_; +}; + +template +inline scope_guard_impl3 make_guard(F fun,P1 p1,P2 p2,P3 p3) +{ + return scope_guard_impl3(fun,p1,p2,p3); +} + +template +class scope_guard_impl4:public scope_guard_impl_base +{ +public: + scope_guard_impl4(F fun,P1 p1,P2 p2,P3 p3,P4 p4): + fun_(fun),p1_(p1),p2_(p2),p3_(p3),p4_(p4){} + ~scope_guard_impl4(){safe_execute(*this);} + void execute(){fun_(p1_,p2_,p3_,p4_);} + +protected: + F fun_; + const P1 p1_; + const P2 p2_; + const P3 p3_; + const P4 p4_; +}; + +template +inline scope_guard_impl4 make_guard( + F fun,P1 p1,P2 p2,P3 p3,P4 p4) +{ + return scope_guard_impl4(fun,p1,p2,p3,p4); +} + +template +class obj_scope_guard_impl0:public scope_guard_impl_base +{ +public: + obj_scope_guard_impl0(Obj& obj,MemFun mem_fun):obj_(obj),mem_fun_(mem_fun){} + ~obj_scope_guard_impl0(){safe_execute(*this);} + void execute(){(obj_.*mem_fun_)();} + +protected: + Obj& obj_; + MemFun mem_fun_; +}; + +template +inline obj_scope_guard_impl0 make_obj_guard(Obj& obj,MemFun mem_fun) +{ + return obj_scope_guard_impl0(obj,mem_fun); +} + +template +class obj_scope_guard_impl1:public scope_guard_impl_base +{ +public: + obj_scope_guard_impl1(Obj& obj,MemFun mem_fun,P1 p1): + obj_(obj),mem_fun_(mem_fun),p1_(p1){} + ~obj_scope_guard_impl1(){safe_execute(*this);} + void execute(){(obj_.*mem_fun_)(p1_);} + +protected: + Obj& obj_; + MemFun mem_fun_; + const P1 p1_; +}; + +template +inline obj_scope_guard_impl1 make_obj_guard( + Obj& obj,MemFun mem_fun,P1 p1) +{ + return obj_scope_guard_impl1(obj,mem_fun,p1); +} + +template +class obj_scope_guard_impl2:public scope_guard_impl_base +{ +public: + obj_scope_guard_impl2(Obj& obj,MemFun mem_fun,P1 p1,P2 p2): + obj_(obj),mem_fun_(mem_fun),p1_(p1),p2_(p2) + {} + ~obj_scope_guard_impl2(){safe_execute(*this);} + void execute(){(obj_.*mem_fun_)(p1_,p2_);} + +protected: + Obj& obj_; + MemFun mem_fun_; + const P1 p1_; + const P2 p2_; +}; + +template +inline obj_scope_guard_impl2 +make_obj_guard(Obj& obj,MemFun mem_fun,P1 p1,P2 p2) +{ + return obj_scope_guard_impl2(obj,mem_fun,p1,p2); +} + +template +class obj_scope_guard_impl3:public scope_guard_impl_base +{ +public: + obj_scope_guard_impl3(Obj& obj,MemFun mem_fun,P1 p1,P2 p2,P3 p3): + obj_(obj),mem_fun_(mem_fun),p1_(p1),p2_(p2),p3_(p3) + {} + ~obj_scope_guard_impl3(){safe_execute(*this);} + void execute(){(obj_.*mem_fun_)(p1_,p2_,p3_);} + +protected: + Obj& obj_; + MemFun mem_fun_; + const P1 p1_; + const P2 p2_; + const P3 p3_; +}; + +template +inline obj_scope_guard_impl3 +make_obj_guard(Obj& obj,MemFun mem_fun,P1 p1,P2 p2,P3 p3) +{ + return obj_scope_guard_impl3(obj,mem_fun,p1,p2,p3); +} + +} /* namespace multi_index::detail */ + +} /* namespace multi_index */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/multi_index/detail/seq_index_node.hpp b/include/boost/multi_index/detail/seq_index_node.hpp new file mode 100644 index 0000000..4867a19 --- /dev/null +++ b/include/boost/multi_index/detail/seq_index_node.hpp @@ -0,0 +1,197 @@ +/* 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. + */ + +#ifndef BOOST_MULTI_INDEX_DETAIL_SEQ_INDEX_NODE_HPP +#define BOOST_MULTI_INDEX_DETAIL_SEQ_INDEX_NODE_HPP + +#include + +namespace boost{ + +namespace multi_index{ + +namespace detail{ + +/* doubly-linked node for use by sequenced_index */ + +struct sequenced_index_node_impl +{ + sequenced_index_node_impl*& prior(){return prior_;} + sequenced_index_node_impl*const & prior()const{return prior_;} + sequenced_index_node_impl*& next(){return next_;} + sequenced_index_node_impl*const & next()const{return next_;} + + /* interoperability with index_iterator */ + + static void increment(sequenced_index_node_impl*& x){x=x->next();} + static void decrement(sequenced_index_node_impl*& x){x=x->prior();} + + /* interoperability with index_proxy */ + + static sequenced_index_node_impl* begin(sequenced_index_node_impl* header) + { + return header->next(); + } + + static sequenced_index_node_impl* end(sequenced_index_node_impl* header) + { + return header; + } + + /* algorithmic stuff */ + + static void link( + sequenced_index_node_impl* x,sequenced_index_node_impl* header) + { + x->prior()=header->prior(); + x->next()=header; + x->prior()->next()=x->next()->prior()=x; + }; + + static void unlink(sequenced_index_node_impl* x) + { + x->prior()->next()=x->next(); + x->next()->prior()=x->prior(); + } + + static void relink( + sequenced_index_node_impl* position,sequenced_index_node_impl* x) + { + unlink(x); + x->prior()=position->prior(); + x->next()=position; + x->prior()->next()=x->next()->prior()=x; + } + + static void relink( + sequenced_index_node_impl* position, + sequenced_index_node_impl* x,sequenced_index_node_impl* y) + { + /* position is assumed not to be in [x,y) */ + + if(x!=y){ + sequenced_index_node_impl* z=y->prior(); + x->prior()->next()=y; + y->prior()=x->prior(); + x->prior()=position->prior(); + z->next()=position; + x->prior()->next()=x; + z->next()->prior()=z; + } + } + + static void reverse(sequenced_index_node_impl* header) + { + sequenced_index_node_impl* x=header; + do{ + sequenced_index_node_impl* y=x->next(); + std::swap(x->prior(),x->next()); + x=y; + }while(x!=header); + } + + static void swap(sequenced_index_node_impl* x,sequenced_index_node_impl* y) + { + /* This swap function does not exchange the header nodes, + * but rather their pointers. This is *not* used for implementing + * sequenced_index::swap. + */ + + if(x->next()!=x){ + if(y->next()!=y){ + std::swap(x->next(),y->next()); + std::swap(x->prior(),y->prior()); + x->next()->prior()=x->prior()->next()=x; + y->next()->prior()=y->prior()->next()=y; + } + else{ + y->next()=x->next(); + y->prior()=x->prior(); + x->next()=x->prior()=x; + y->next()->prior()=y->prior()->next()=y; + } + } + else if(y->next()!=y){ + x->next()=y->next(); + x->prior()=y->prior(); + y->next()=y->prior()=y; + x->next()->prior()=x->prior()->next()=x; + } + } + +private: + sequenced_index_node_impl(); + + sequenced_index_node_impl* prior_; + sequenced_index_node_impl* next_; +}; + +template +struct sequenced_index_node_trampoline:sequenced_index_node_impl{}; + +template +struct sequenced_index_node:Super,sequenced_index_node_trampoline +{ + sequenced_index_node_impl*& prior(){return impl_type::prior();} + sequenced_index_node_impl*const & prior()const{return impl_type::prior();} + sequenced_index_node_impl*& next(){return impl_type::next();} + sequenced_index_node_impl*const & next()const{return impl_type::next();} + + sequenced_index_node_impl* impl() + {return static_cast(this);} + const sequenced_index_node_impl* impl()const + {return static_cast(this);} + + static sequenced_index_node* from_impl(sequenced_index_node_impl *x) + {return static_cast(static_cast(x));} + static const sequenced_index_node* from_impl( + const sequenced_index_node_impl* x) + { + return static_cast( + static_cast(x)); + } + + /* interoperability with index_iterator */ + + static void increment(sequenced_index_node*& x) + { + sequenced_index_node_impl* xi=x->impl(); + impl_type::increment(xi); + x=from_impl(xi); + } + + static void decrement(sequenced_index_node*& x) + { + sequenced_index_node_impl* xi=x->impl(); + impl_type::decrement(xi); + x=from_impl(xi); + } + + /* interoperability with index_proxy */ + + static sequenced_index_node* begin(sequenced_index_node* header) + { + return from_impl(impl_type::begin(header->impl())); + } + + static sequenced_index_node* end(sequenced_index_node* header) + { + return from_impl(impl_type::end(header->impl())); + } + +private: + typedef sequenced_index_node_trampoline impl_type; +}; + +} /* namespace multi_index::detail */ + +} /* namespace multi_index */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/multi_index/detail/seq_index_ops.hpp b/include/boost/multi_index/detail/seq_index_ops.hpp new file mode 100644 index 0000000..a4ce908 --- /dev/null +++ b/include/boost/multi_index/detail/seq_index_ops.hpp @@ -0,0 +1,164 @@ +/* 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. + */ + +#ifndef BOOST_MULTI_INDEX_DETAIL_SEQ_INDEX_OPS_HPP +#define BOOST_MULTI_INDEX_DETAIL_SEQ_INDEX_OPS_HPP + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include +#include +#include +#include + +namespace boost{ + +namespace multi_index{ + +namespace detail{ + +/* Common code for sequenced_index memfuns having templatized and + * non-templatized versions. + */ + +template +void sequenced_index_remove(SequencedIndex& x,Predicate pred) +{ + typedef typename SequencedIndex::iterator iterator; + iterator first=x.begin(),last=x.end(); + while(first!=last){ + if(pred(*first))x.erase(first++); + else ++first; + } +} + +template +void sequenced_index_unique(SequencedIndex& x,BinaryPredicate binary_pred) +{ + typedef typename SequencedIndex::iterator iterator; + iterator first=x.begin(); + iterator last=x.end(); + if(first!=last){ + for(iterator middle=first;++middle!=last;middle=first){ + if(binary_pred(*middle,*first))x.erase(middle); + else first=middle; + } + } +} + +template +void sequenced_index_merge(SequencedIndex& x,SequencedIndex& y,Compare comp) +{ + typedef typename SequencedIndex::iterator iterator; + if(x!=y){ + iterator first0=x.begin(),last0=x.end(); + iterator first1=y.begin(),last1=y.end(); + while(first0!=last0&&first1!=last1){ + if(comp(*first1,*first0))x.splice(first0,y,first1++); + else ++first0; + } + x.splice(last0,y,first1,last1); + } +} + +/* sorting */ + +/* auxiliary stuff */ + +template +void sequenced_index_collate( + sequenced_index_node_impl* x,sequenced_index_node_impl* y,Compare comp + BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE(Node)) +{ + sequenced_index_node_impl* first0=x->next(); + sequenced_index_node_impl* last0=x; + sequenced_index_node_impl* first1=y->next(); + sequenced_index_node_impl* last1=y; + while(first0!=last0&&first1!=last1){ + if(comp(Node::from_impl(first1)->value,Node::from_impl(first0)->value)){ + sequenced_index_node_impl* tmp=first1->next(); + sequenced_index_node_impl::relink(first0,first1); + first1=tmp; + } + else first0=first0->next(); + } + sequenced_index_node_impl::relink(last0,first1,last1); +} + +template +void sequenced_index_sort(Node* header,Compare comp) +{ + /* Musser's mergesort, see http://www.cs.rpi.edu/~musser/gp/List/lists1.html. + * The implementation is a little convoluted: in the original code + * counter elements and carry are std::lists: here we do not want + * to use multi_index instead, so we do things at a lower level, managing + * directly the internal node representation. + * Incidentally, the implementations I've seen of this algorithm (SGI, + * Dinkumware, STLPort) are not exception-safe: this is. Moreover, we do not + * use any dynamic storage. + */ + + if(header->next()==header->impl()|| + header->next()->next()==header->impl())return; + + BOOST_STATIC_CONSTANT( + std::size_t, + max_fill=(std::size_t)std::numeric_limits::digits+1); + + aligned_storage< + sizeof(sequenced_index_node_impl)> carry_spc; + sequenced_index_node_impl& carry= + *static_cast(carry_spc.address()); + aligned_storage< + sizeof( + sequenced_index_node_impl[max_fill])> counter_spc; + sequenced_index_node_impl* counter= + static_cast(counter_spc.address()); + std::size_t fill=0; + + carry.prior()=carry.next()=&carry; + counter[0].prior()=counter[0].next()=&counter[0]; + + BOOST_TRY{ + while(header->next()!=header->impl()){ + sequenced_index_node_impl::relink(carry.next(),header->next()); + std::size_t i=0; + while(i(&carry,&counter[i++],comp); + } + sequenced_index_node_impl::swap(&carry,&counter[i]); + if(i==fill){ + ++fill; + counter[fill].prior()=counter[fill].next()=&counter[fill]; + } + } + + for(std::size_t i=1;i(&counter[i],&counter[i-1],comp); + } + sequenced_index_node_impl::swap(header->impl(),&counter[fill-1]); + } + BOOST_CATCH(...) + { + sequenced_index_node_impl::relink(header->impl(),carry.next(),&carry); + for(std::size_t i=0;i<=fill;++i){ + sequenced_index_node_impl::relink( + header->impl(),counter[i].next(),&counter[i]); + } + BOOST_RETHROW; + } + BOOST_CATCH_END +} + +} /* namespace multi_index::detail */ + +} /* namespace multi_index */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/multi_index/detail/unbounded.hpp b/include/boost/multi_index/detail/unbounded.hpp new file mode 100644 index 0000000..3a76e02 --- /dev/null +++ b/include/boost/multi_index/detail/unbounded.hpp @@ -0,0 +1,35 @@ +/* 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. + */ + +#ifndef BOOST_MULTI_INDEX_DETAIL_UNBOUNDED_HPP +#define BOOST_MULTI_INDEX_DETAIL_UNBOUNDED_HPP + +namespace boost{ + +namespace multi_index{ + +/* dummy type and variable for use in ordered_index::range() */ + +namespace detail{ + +struct unbounded_type{}; + +} /* namespace multi_index::detail */ + +namespace{ + +detail::unbounded_type unbounded_obj=detail::unbounded_type(); +detail::unbounded_type& unbounded=unbounded_obj; + +} /* unnamed */ + +} /* namespace multi_index */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/multi_index/detail/value_compare.hpp b/include/boost/multi_index/detail/value_compare.hpp new file mode 100644 index 0000000..4b68687 --- /dev/null +++ b/include/boost/multi_index/detail/value_compare.hpp @@ -0,0 +1,48 @@ +/* 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. + */ + +#ifndef BOOST_MULTI_INDEX_DETAIL_VALUE_COMPARE_HPP +#define BOOST_MULTI_INDEX_DETAIL_VALUE_COMPARE_HPP + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include + +namespace boost{ + +namespace multi_index{ + +namespace detail{ + +template +struct value_comparison:std::binary_function +{ + value_comparison(KeyFromValue key_=KeyFromValue(),Compare comp_=Compare()): + key(key_),comp(comp_) + { + } + + bool operator()( + typename call_traits::param_type x, + typename call_traits::param_type y) + { + return comp(key(x),key(y)); + } + +private: + KeyFromValue key; + Compare comp; +}; + +} /* namespace multi_index::detail */ + +} /* namespace multi_index */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/multi_index/identity.hpp b/include/boost/multi_index/identity.hpp new file mode 100644 index 0000000..b001c58 --- /dev/null +++ b/include/boost/multi_index/identity.hpp @@ -0,0 +1,119 @@ +/* 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. + */ + +#ifndef BOOST_MULTI_INDEX_IDENTITY_HPP +#define BOOST_MULTI_INDEX_IDENTITY_HPP + +#include +#include +#include +#include +#include + +namespace boost{ + +template class reference_wrapper; /* fwd decl. */ + +namespace multi_index{ + +namespace detail{ + +/* identity is a do-nothing key extractor that returns the [const] Type& + * object passed. + * Additionally, identity is overloaded to support referece_wrappers + * of Type and "chained pointers" to Type's. By chained pointer to Type we + * mean a type P such that, given a p of type P + * *...n...*x is convertible to Type&, for some n>=1. + * Examples of chained pointers are raw and smart pointers, iterators and + * arbitrary combinations of these (vg. Type** or auto_ptr.) + */ + +/* NB. Some overloads of operator() have an extra dummy parameter int=0. + * This is so because MSVC++ 6.0 otherwise *incorrectly* regards these + * overloads as specializations of a previous member function template. + * Left for all compilers as it does no harm. + */ + +template +struct const_identity_base +{ + typedef Type result_type; + + template + Type& operator()(const ChainedPtr& x)const + { + return operator()(*x); + } + + Type& operator()(Type& x)const + { + return x; + } + + Type& operator()(const reference_wrapper& x)const + { + return x.get(); + } + + Type& operator()( + const reference_wrapper::type>& x)const + { + return x.get(); + } +}; + +template +struct non_const_identity_base +{ + typedef Type result_type; + + /* templatized for pointer-like types */ + + template + Type& operator()(const ChainedPtr& x)const + { + return operator()(*x); + } + + const Type& operator()(const Type& x,int=0)const + { + return x; + } + + Type& operator()(Type& x)const + { + return x; + } + + const Type& operator()(const reference_wrapper& x,int=0)const + { + return x.get(); + } + + Type& operator()(const reference_wrapper& x)const + { + return x.get(); + } +}; + +} /* namespace multi_index::detail */ + +template +struct identity: + mpl::if_c< + is_const::value, + detail::const_identity_base,detail::non_const_identity_base + >::type +{ +}; + +} /* namespace multi_index */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/multi_index/identity_fwd.hpp b/include/boost/multi_index/identity_fwd.hpp new file mode 100644 index 0000000..40b0533 --- /dev/null +++ b/include/boost/multi_index/identity_fwd.hpp @@ -0,0 +1,22 @@ +/* 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. + */ + +#ifndef BOOST_MULTI_INDEX_IDENTITY_HPP +#define BOOST_MULTI_INDEX_IDENTITY_HPP + +namespace boost{ + +namespace multi_index{ + +template struct identity; + +} /* namespace multi_index */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/multi_index/indexed_by.hpp b/include/boost/multi_index/indexed_by.hpp new file mode 100644 index 0000000..07f0069 --- /dev/null +++ b/include/boost/multi_index/indexed_by.hpp @@ -0,0 +1,68 @@ +/* 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. + */ + +#ifndef BOOST_MULTI_INDEX_INDEXED_BY_HPP +#define BOOST_MULTI_INDEX_INDEXED_BY_HPP + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include +#include +#include +#include + +/* An alias to mpl::vector used to hide MPL from the user. + * indexed_by contains the index specifiers for instantiation + * of a multi_index_container. + */ + +/* This user_definable macro limits the number of elements of an index list; + * useful for shortening resulting symbol names (MSVC++ 6.0, for instance, + * has problems coping with very long symbol names.) + */ + +#if !defined(BOOST_MULTI_INDEX_LIMIT_INDEXED_BY_SIZE) +#if defined(BOOST_MSVC)&&(BOOST_MSVC<1300) +#define BOOST_MULTI_INDEX_LIMIT_INDEXED_BY_SIZE 5 +#else +#define BOOST_MULTI_INDEX_LIMIT_INDEXED_BY_SIZE BOOST_MPL_LIMIT_VECTOR_SIZE +#endif +#endif + +#if BOOST_MULTI_INDEX_LIMIT_INDEXED_BY_SIZE +struct indexed_by: + mpl::vector +{ +}; + +} /* namespace multi_index */ + +} /* namespace boost */ + +#undef BOOST_MULTI_INDEX_INDEXED_BY_TEMPLATE_PARM +#undef BOOST_MULTI_INDEX_INDEXED_BY_SIZE + +#endif diff --git a/include/boost/multi_index/key_extractors.hpp b/include/boost/multi_index/key_extractors.hpp new file mode 100644 index 0000000..551b31e --- /dev/null +++ b/include/boost/multi_index/key_extractors.hpp @@ -0,0 +1,17 @@ +/* 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. + */ + +#ifndef BOOST_MULTI_INDEX_KEY_EXTRACTORS_HPP +#define BOOST_MULTI_INDEX_KEY_EXTRACTORS_HPP + +#include +#include +#include +#include + +#endif diff --git a/include/boost/multi_index/mem_fun.hpp b/include/boost/multi_index/mem_fun.hpp new file mode 100644 index 0000000..fd599f7 --- /dev/null +++ b/include/boost/multi_index/mem_fun.hpp @@ -0,0 +1,171 @@ +/* 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. + */ + +#ifndef BOOST_MULTI_INDEX_MEM_FUN_HPP +#define BOOST_MULTI_INDEX_MEM_FUN_HPP + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include + +namespace boost{ + +template class reference_wrapper; /* fwd decl. */ + +namespace multi_index{ + +/* mem_fun implements a read-only key extractor based on a given non-const + * member function of a class. + * const_mem_fun does the same for const member functions. + * Additionally, mem_fun and const_mem_fun are overloaded to support + * referece_wrappers of T and "chained pointers" to T's. By chained pointer + * to T we mean a type P such that, given a p of Type P + * *...n...*x is convertible to T&, for some n>=1. + * Examples of chained pointers are raw and smart pointers, iterators and + * arbitrary combinations of these (vg. T** or auto_ptr.) + */ + +template +struct const_mem_fun +{ + typedef typename remove_reference::type result_type; + + template + Type operator()(const ChainedPtr& x)const + { + return operator()(*x); + } + + Type operator()(const Class& x)const + { + return (x.*PtrToMemberFunction)(); + } + + Type operator()(const reference_wrapper& x)const + { + return operator()(x.get()); + } + + Type operator()(const reference_wrapper& x)const + { + return operator()(x.get()); + } +}; + +template +struct mem_fun +{ + typedef typename remove_reference::type result_type; + + template + Type operator()(const ChainedPtr& x)const + { + return operator()(*x); + } + + Type operator()(Class& x)const + { + return (x.*PtrToMemberFunction)(); + } + + Type operator()(const reference_wrapper& x)const + { + return operator()(x.get()); + } +}; + +/* MSVC++ 6.0 has problems with const member functions as non-type template + * parameters, somehow it takes them as non-const. mem_fun_explicit workarounds + * this defficiency by accepting an extra type parameter that specifies the + * signature of he member function. The workaround was found at: + * Daniel, C.:"Re: weird typedef problem in VC", + * news:microsoft.public.vc.language, 21st nov 2002, + * http://groups.google.com/groups? + * hl=en&lr=&ie=UTF-8&selm=ukwvg3O0BHA.1512%40tkmsftngp05 + */ + +template< + class Class,typename Type, + typename PtrToMemberFunctionType,PtrToMemberFunctionType PtrToMemberFunction> +struct const_mem_fun_explicit +{ + typedef typename remove_reference::type result_type; + + template + Type operator()(const ChainedPtr& x)const + { + return operator()(*x); + } + + Type operator()(const Class& x)const + { + return (x.*PtrToMemberFunction)(); + } + + Type operator()(const reference_wrapper& x)const + { + return operator()(x.get()); + } + + Type operator()(const reference_wrapper& x)const + { + return operator()(x.get()); + } +}; + +template< + class Class,typename Type, + typename PtrToMemberFunctionType,PtrToMemberFunctionType PtrToMemberFunction> +struct mem_fun_explicit +{ + typedef typename remove_reference::type result_type; + + template + Type operator()(const ChainedPtr& x)const + { + return operator()(*x); + } + + Type operator()(Class& x)const + { + return (x.*PtrToMemberFunction)(); + } + + Type operator()(const reference_wrapper& x)const + { + return operator()(x.get()); + } +}; + +/* BOOST_MULTI_INDEX_CONST_MEM_FUN and BOOST_MULTI_INDEX_MEM_FUN resolve to + * mem_fun_explicit for MSVC++ 6.0 and to [const_]mem_fun otherwise. + */ + +#if defined(BOOST_MSVC)&&(BOOST_MSVC<1300) + +#define BOOST_MULTI_INDEX_CONST_MEM_FUN(Class,Type,MemberFunName) \ +::boost::multi_index::const_mem_fun_explicit<\ + Class,Type,Type (Class::*)()const,&Class::MemberFunName> +#define BOOST_MULTI_INDEX_MEM_FUN(Class,Type,MemberFunName) \ +::boost::multi_index::mem_fun_explicit<\ + Class,Type,Type (Class::*)(),&Class::MemberFunName> + +#else + +#define BOOST_MULTI_INDEX_CONST_MEM_FUN(Class,Type,MemberFunName) \ +::boost::multi_index::const_mem_fun +#define BOOST_MULTI_INDEX_MEM_FUN(Class,Type,MemberFunName) \ +::boost::multi_index::mem_fun + +#endif + +} /* namespace multi_index */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/multi_index/member.hpp b/include/boost/multi_index/member.hpp new file mode 100644 index 0000000..8ec15a0 --- /dev/null +++ b/include/boost/multi_index/member.hpp @@ -0,0 +1,228 @@ +/* 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. + */ + +#ifndef BOOST_MULTI_INDEX_MEMBER_HPP +#define BOOST_MULTI_INDEX_MEMBER_HPP + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include +#include + +namespace boost{ + +template class reference_wrapper; /* fwd decl. */ + +namespace multi_index{ + +namespace detail{ + +/* member is a read/write key extractor for accessing a given + * member of a class. + * Additionally, member is overloaded to support referece_wrappers + * of T and "chained pointers" to T's. By chained pointer to T we mean + * a type P such that, given a p of Type P + * *...n...*x is convertible to T&, for some n>=1. + * Examples of chained pointers are raw and smart pointers, iterators and + * arbitrary combinations of these (vg. T** or auto_ptr.) + */ + +/* NB. Some overloads of operator() have an extra dummy parameter int=0. + * This is so because MSVC++ 6.0 otherwise *incorrectly* regards these + * overloads as specializations of a previous member function template. + * Left for all compilers as it does no harm. + */ + +template +struct const_member_base +{ + typedef Type result_type; + + template + Type& operator()(const ChainedPtr& x)const + { + return operator()(*x); + } + + Type& operator()(const Class& x)const + { + return x.*PtrToMember; + } + + Type& operator()(const reference_wrapper& x)const + { + return operator()(x.get()); + } + + Type& operator()(const reference_wrapper x)const + { + return operator()(x.get()); + } +}; + +template +struct non_const_member_base +{ + typedef Type result_type; + + template + Type& operator()(const ChainedPtr& x)const + { + return operator()(*x); + } + + const Type& operator()(const Class& x,int=0)const + { + return x.*PtrToMember; + } + + Type& operator()(Class& x)const + { + return x.*PtrToMember; + } + + const Type& operator()(const reference_wrapper& x,int=0)const + { + return operator()(x.get()); + } + + Type& operator()(const reference_wrapper& x)const + { + return operator()(x.get()); + } +}; + +} /* namespace multi_index::detail */ + +template +struct member: + mpl::if_c< + is_const::value, + detail::const_member_base, + detail::non_const_member_base + >::type +{ +}; + +namespace detail{ + +/* MSVC++ 6.0 does not support properly pointers to members as + * non-type template arguments, as reported in + * http://support.microsoft.com/default.aspx?scid=kb;EN-US;249045 + * We provide an alternative to member<> accepting offsets instead + * of pointers to members. This happens to work even for non-POD + * types (although the standard forbids use of offsetof on these), + * so it serves as a workaround in this compiler for all practical + * purposes. + * Surprisingly enough, other compilers (Intel C++ 7.1 at least) + * have similar bugs. This replacement of member<> can be used for + * them too. + */ + +template +struct const_member_offset_base +{ + typedef Type result_type; + + template + Type& operator()(const ChainedPtr& x)const + { + return operator()(*x); + } + + Type& operator()(const Class& x)const + { + return *static_cast( + static_cast( + static_cast( + static_cast(&x))+OffsetOfMember)); + } + + Type& operator()(const reference_wrapper& x)const + { + return operator()(x.get()); + } + + Type& operator()(const reference_wrapper& x)const + { + return operator()(x.get()); + } +}; + +template +struct non_const_member_offset_base +{ + typedef Type result_type; + + template + Type& operator()(const ChainedPtr& x)const + { + return operator()(*x); + } + + const Type& operator()(const Class& x,int=0)const + { + return *static_cast( + static_cast( + static_cast( + static_cast(&x))+OffsetOfMember)); + } + + Type& operator()(Class& x)const + { + return *static_cast( + static_cast( + static_cast(static_cast(&x))+OffsetOfMember)); + } + + const Type& operator()(const reference_wrapper& x,int=0)const + { + return operator()(x.get()); + } + + Type& operator()(const reference_wrapper& x)const + { + return operator()(x.get()); + } +}; + +} /* namespace multi_index::detail */ + +template +struct member_offset: + mpl::if_c< + is_const::value, + detail::const_member_offset_base, + detail::non_const_member_offset_base + >::type +{ +}; + +/* A proposal has been issued to add a defect macro in Boost.Config to detect + * this problem with pointer to members as template arguments. While + * the macro gets into the library, we follow our own heuristics in order to + * define BOOST_MULTI_INDEX_MEMBER as a convenient wrapper of member<> and + * member_offset<> + */ + +#if defined(BOOST_NO_POINTER_TO_MEMBER_TEMPLATE_PARAMETERS) ||\ + defined(BOOST_MSVC)&&(BOOST_MSVC<1300) ||\ + defined(BOOST_INTEL_CXX_VERSION)&&defined(_MSC_VER)&&\ + (BOOST_INTEL_CXX_VERSION<=700) +#define BOOST_MULTI_INDEX_MEMBER(Class,Type,MemberName) \ +::boost::multi_index::member_offset +#else +#define BOOST_MULTI_INDEX_MEMBER(Class,Type,MemberName) \ +::boost::multi_index::member +#endif + +} /* namespace multi_index */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/multi_index/ordered_index.hpp b/include/boost/multi_index/ordered_index.hpp new file mode 100644 index 0000000..ffdd185 --- /dev/null +++ b/include/boost/multi_index/ordered_index.hpp @@ -0,0 +1,1124 @@ +/* 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. + * + * The internal implementation of red-black trees is based on that of SGI STL + * stl_tree.h file: + * + * 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. + * + */ + +#ifndef BOOST_MULTI_INDEX_ORDERED_INDEX_HPP +#define BOOST_MULTI_INDEX_ORDERED_INDEX_HPP + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING) +#define BOOST_MULTI_INDEX_ORD_INDEX_CHECK_INVARIANT \ + detail::scope_guard BOOST_JOIN(check_invariant_,__LINE__)= \ + detail::make_obj_guard(*this,&ordered_index::check_invariant_); \ + BOOST_JOIN(check_invariant_,__LINE__).touch(); +#else +#define BOOST_MULTI_INDEX_ORD_INDEX_CHECK_INVARIANT +#endif + +namespace boost{ + +namespace multi_index{ + +namespace detail{ + +/* ordered_index adds a layer of indexing to a given Super */ + +/* Most of the implementation of unique and non-unique indices is + * shared. We tell from one another on instantiation time by using + * these tags. + */ + +struct ordered_unique_tag{}; +struct ordered_non_unique_tag{}; + +template< + typename KeyFromValue,typename Compare, + typename Super,typename TagList,typename Category +> + +#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE) +#if BOOST_WORKAROUND(BOOST_MSVC,<1300) +class ordered_index: + BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS Super, + public index_proxy > +#else +class ordered_index: + BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS Super, + public safe_container< + ordered_index > +#endif +#else +class ordered_index: + BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS Super +#endif + +{ +protected: + typedef ordered_index_node< + typename Super::node_type> node_type; + +public: + /* types */ + + typedef typename KeyFromValue::result_type key_type; + typedef typename node_type::value_type value_type; + typedef KeyFromValue key_from_value; + typedef Compare key_compare; + typedef value_comparison< + value_type,KeyFromValue,Compare> value_compare; + typedef tuple ctor_args; + typedef typename Super::final_allocator_type allocator_type; + typedef typename allocator_type::reference reference; + typedef typename allocator_type::const_reference const_reference; + +#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE) +#if BOOST_WORKAROUND(BOOST_MSVC,<1300) + typedef index_iterator iterator; + typedef index_iterator const_iterator; +#else + typedef index_iterator iterator; + typedef index_iterator const_iterator; +#endif +#else + typedef index_iterator iterator; + typedef index_iterator const_iterator; +#endif + + 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 typename + boost::reverse_iterator reverse_iterator; + typedef typename + boost::reverse_iterator const_reverse_iterator; + typedef typename TagList::type tag_list; + +protected: + typedef typename Super::final_node_type final_node_type; + typedef tuples::cons< + ctor_args, + typename Super::ctor_args_list> ctor_args_list; + typedef typename mpl::push_front< + typename Super::index_type_list, + ordered_index>::type index_type_list; + typedef typename mpl::push_front< + typename Super::iterator_type_list, + iterator>::type iterator_type_list; + typedef typename mpl::push_front< + typename Super::const_iterator_type_list, + const_iterator>::type const_iterator_type_list; + typedef typename Super::copy_map_type copy_map_type; + +private: +#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE) +#if BOOST_WORKAROUND(BOOST_MSVC,<1300) + typedef index_proxy< + ordered_index_node< + typename Super::node_type> > safe_super; +#else + typedef safe_container safe_super; +#endif +#endif + + typedef typename call_traits< + value_type>::param_type value_param_type; + typedef typename call_traits< + key_type>::param_type key_param_type; + +public: + + /* construct/copy/destroy + * Default and copy ctors are in the protected section as indices are + * not supposed to be created on their own. No range ctor either. + */ + + ordered_index& operator=( + const ordered_index& x) + { + BOOST_MULTI_INDEX_ORD_INDEX_CHECK_INVARIANT; + this->final()=x.final(); + return *this; + } + + allocator_type get_allocator()const + { + return this->final().get_allocator(); + } + + /* iterators */ + + iterator begin(){return make_iterator(leftmost());} + const_iterator begin()const{return make_iterator(leftmost());} + iterator end(){return make_iterator(header());} + const_iterator end()const{return make_iterator(header());} + reverse_iterator rbegin(){return make_reverse_iterator(end());} + const_reverse_iterator rbegin()const{return make_reverse_iterator(end());} + reverse_iterator rend(){return make_reverse_iterator(begin());} + const_reverse_iterator rend()const{return make_reverse_iterator(begin());} + + /* capacity */ + + bool empty()const{return this->final_empty_();} + size_type size()const{return this->final_size_();} + size_type max_size()const{return this->final_max_size_();} + + /* modifiers */ + + std::pair insert(value_param_type x) + { + BOOST_MULTI_INDEX_ORD_INDEX_CHECK_INVARIANT; + std::pair p=this->final_insert_(x); + /* "this->" not required by std, but CW9.2 seems to need it */ + + return std::pair(make_iterator(p.first),p.second); + } + + iterator insert(iterator position,value_param_type x) + { + BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position); + BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this); + BOOST_MULTI_INDEX_ORD_INDEX_CHECK_INVARIANT; + std::pair p=final_insert_( + x,static_cast(position.get_node())); + return make_iterator(p.first); + } + + template + void insert(InputIterator first,InputIterator last) + { + BOOST_MULTI_INDEX_ORD_INDEX_CHECK_INVARIANT; + iterator hint=end(); + for(;first!=last;++first)hint=insert(hint,*first); + } + + void erase(iterator position) + { + BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position); + BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(position); + BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this); + BOOST_MULTI_INDEX_ORD_INDEX_CHECK_INVARIANT; + +#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE) + /* MSVC++ 6.0 optimizer on safe mode code chokes if this + * this is not added. Left it for all compilers as it does no + * harm. + */ + + position.detach(); +#endif + + final_erase_(static_cast(position.get_node())); + } + + size_type erase(key_param_type x) + { + BOOST_MULTI_INDEX_ORD_INDEX_CHECK_INVARIANT; + std::pair p=equal_range(x); + size_type s=0; + while(p.first!=p.second){ + erase(p.first++); + ++s; + } + return s; + } + + void erase(iterator first,iterator last) + { + BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(first); + BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(last); + BOOST_MULTI_INDEX_CHECK_IS_OWNER(first,*this); + BOOST_MULTI_INDEX_CHECK_IS_OWNER(last,*this); + BOOST_MULTI_INDEX_CHECK_VALID_RANGE(first,last); + BOOST_MULTI_INDEX_ORD_INDEX_CHECK_INVARIANT; + while(first!=last){ + erase(first++); + } + } + + bool replace(iterator position,value_param_type x) + { + BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position); + BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(position); + BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this); + BOOST_MULTI_INDEX_ORD_INDEX_CHECK_INVARIANT; + return final_replace_( + x,static_cast(position.get_node())); + } + + template + bool modify(iterator position,Modifier mod) + { + BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position); + BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(position); + BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this); + BOOST_MULTI_INDEX_ORD_INDEX_CHECK_INVARIANT; + +#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE) + /* MSVC++ 6.0 optimizer on safe mode code chokes if this + * this is not added. Left it for all compilers as it does no + * harm. + */ + + position.detach(); +#endif + + return final_modify_( + mod,static_cast(position.get_node())); + } + + template + bool modify_key(iterator position,Modifier mod) + { + BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position); + BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(position); + BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this); + BOOST_MULTI_INDEX_ORD_INDEX_CHECK_INVARIANT; + return modify( + position,modify_key_adaptor(mod,key)); + } + + void swap(ordered_index& x) + { + BOOST_MULTI_INDEX_ORD_INDEX_CHECK_INVARIANT; + final_swap_(x.final()); + } + + void clear() + { + BOOST_MULTI_INDEX_ORD_INDEX_CHECK_INVARIANT; + erase(begin(),end()); + } + + /* observers */ + + key_from_value key_extractor()const{return key;} + key_compare key_comp()const{return comp;} + value_compare value_comp()const{return value_compare(key,comp);} + + /* set operations */ + + /* no need to provide non-const versions as + * ordered_index::iterator==ordered_index::const_iterator + */ + + template + const_iterator find(const CompatibleKey& x)const + { + return make_iterator(ordered_index_find(header(),key,x,comp)); + } + + template + const_iterator find( + const CompatibleKey& x,const CompatibleCompare& comp)const + { + return make_iterator(ordered_index_find(header(),key,x,comp)); + } + + template + size_type count(const CompatibleKey& x)const + { + return count(x,comp); + } + + template + size_type count(const CompatibleKey& x,const CompatibleCompare& comp)const + { + std::pair p=equal_range(x,comp); + size_type n=std::distance(p.first,p.second); + return n; + } + + template + const_iterator lower_bound(const CompatibleKey& x)const + { + return make_iterator(ordered_index_lower_bound(header(),key,x,comp)); + } + + template + const_iterator lower_bound( + const CompatibleKey& x,const CompatibleCompare& comp)const + { + return make_iterator(ordered_index_lower_bound(header(),key,x,comp)); + } + + template + const_iterator upper_bound(const CompatibleKey& x)const + { + return make_iterator(ordered_index_upper_bound(header(),key,x,comp)); + } + + template + const_iterator upper_bound( + const CompatibleKey& x,const CompatibleCompare& comp)const + { + return make_iterator(ordered_index_upper_bound(header(),key,x,comp)); + } + + template + std::pair equal_range( + const CompatibleKey& x)const + { + return equal_range(x,comp); + } + + template + std::pair equal_range( + const CompatibleKey& x,const CompatibleCompare& comp)const + { + return std::pair( + lower_bound(x,comp),upper_bound(x,comp)); + } + + /* range */ + + /* no need to provide non-const version as + * ordered_index::iterator==ordered_index::const_iterator + */ + + template + std::pair + range(LowerBounder lower,UpperBounder upper)const + { + std::pair p( + lower_range(lower),upper_range(upper)); + if(p.second!=end()&&(p.first==end()||comp(key(*p.second),key(*p.first)))){ + p.second=p.first; + } + return p; + } + +BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS: + ordered_index(const ctor_args_list& args_list,const allocator_type& al): + Super(args_list.get_tail(),al), + +#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)&&\ + BOOST_WORKAROUND(BOOST_MSVC,<1300) + safe_super(final_header()), +#endif + + key(tuples::get<0>(args_list.get_head())), + comp(tuples::get<1>(args_list.get_head())) + { + empty_initialize(); + } + + ordered_index( + const ordered_index& x): + Super(x), + +#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)&&\ + BOOST_WORKAROUND(BOOST_MSVC,<1300) + safe_super(final_header()), +#endif + + key(x.key), + comp(x.comp) + { + /* Copy ctor just takes the key and compare objects from x. The rest is + * done in subsequent call to copy_(). + */ + } + + ~ordered_index() + { + /* the container is guaranteed to be empty by now */ + } + +#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE) + iterator make_iterator(node_type* node){return iterator(node,this);} + const_iterator make_iterator(node_type* node)const + {return const_iterator(node,const_cast(this));} +#else + iterator make_iterator(node_type* node){return iterator(node);} + const_iterator make_iterator(node_type* node)const + {return const_iterator(node);} +#endif + + void copy_( + const ordered_index& x, + const copy_map_type& map) + { + if(!x.root()){ + empty_initialize(); + } + else{ + header()->color()=x.header()->color(); + + node_type* root_cpy=map.find(static_cast(x.root())); + header()->parent()=root_cpy->impl(); + + node_type* leftmost_cpy=map.find( + static_cast(x.leftmost())); + header()->left()=leftmost_cpy->impl(); + + node_type* rightmost_cpy=map.find( + static_cast(x.rightmost())); + header()->right()=rightmost_cpy->impl(); + + typedef typename copy_map_type::const_iterator copy_map_iterator; + for(copy_map_iterator it=map.begin();it!=map.end();++it){ + node_type* org=it->first; + node_type* cpy=it->second; + + cpy->color()=org->color(); + + ordered_index_node_impl* parent_org=org->parent(); + if(!parent_org)cpy->parent()=0; + else{ + node_type* parent_cpy=map.find( + static_cast(node_type::from_impl(parent_org))); + cpy->parent()=parent_cpy->impl(); + if(parent_org->left()==org->impl()){ + parent_cpy->left()=cpy->impl(); + } + else if(parent_org->right()==org->impl()){ + /* header() does not satisfy this nor the previous check */ + parent_cpy->right()=cpy->impl(); + } + } + + if(!org->left())cpy->left()=0; + if(!org->right())cpy->right()=0; + } + } + + Super::copy_(x,map); + } + + node_type* insert_(value_param_type v,node_type* x) + { + node_type* res=link2(key(v),x,Category()); + if(res!=x)return res; + else{ + BOOST_TRY{ + res=static_cast(Super::insert_(v,x)); + if(res!=x){ + ordered_index_node_impl::rebalance_for_erase( + x->impl(),header()->parent(),header()->left(),header()->right()); + } + return res; + } + BOOST_CATCH(...){ + ordered_index_node_impl::rebalance_for_erase( + x->impl(),header()->parent(),header()->left(),header()->right()); + BOOST_RETHROW; + } + BOOST_CATCH_END + } + } + + node_type* insert_(value_param_type v,node_type* position,node_type* x) + { + node_type* res=link3(key(v),position,x,Category()); + if(res!=x)return res; + else{ + BOOST_TRY{ + res=static_cast(Super::insert_(v,position,x)); + if(res!=x){ + ordered_index_node_impl::rebalance_for_erase( + x->impl(),header()->parent(),header()->left(),header()->right()); + } + return res; + } + BOOST_CATCH(...){ + ordered_index_node_impl::rebalance_for_erase( + x->impl(),header()->parent(),header()->left(),header()->right()); + BOOST_RETHROW; + } + BOOST_CATCH_END + } + } + + void erase_(node_type* x) + { + Super::erase_(x); + ordered_index_node_impl::rebalance_for_erase( + x->impl(),header()->parent(),header()->left(),header()->right()); + +#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE) + detach_iterators(x); +#endif + } + + void swap_(ordered_index& x) + { + std::swap(key,x.key); + std::swap(comp,x.comp); + +#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE) + safe_super::swap(x); +#endif + + Super::swap_(x); + } + + bool replace_(value_param_type v,node_type* x) + { + if(!comp(key(v),key(x->value))&& + !comp(key(x->value),key(v))){ + return Super::replace_(v,x); + } + + node_type* prior=x; + node_type::decrement(prior); + node_type* next=x; + node_type::increment(next); + + ordered_index_node_impl::rebalance_for_erase( + x->impl(),header()->parent(),header()->left(),header()->right()); + + BOOST_TRY{ + if(link2(key(v),x,Category())!=x){ + ordered_index_node_impl::restore( + x->impl(),prior->impl(),next->impl(),header()->impl()); + return false; + } + + BOOST_TRY{ + if(!Super::replace_(v,x)){ + ordered_index_node_impl::rebalance_for_erase( + x->impl(),header()->parent(),header()->left(),header()->right()); + ordered_index_node_impl::restore( + x->impl(),prior->impl(),next->impl(),header()->impl()); + return false; + } + else return true; + } + BOOST_CATCH(...){ + ordered_index_node_impl::rebalance_for_erase( + x->impl(),header()->parent(),header()->left(),header()->right()); + BOOST_RETHROW; + } + BOOST_CATCH_END + } + BOOST_CATCH(...){ + ordered_index_node_impl::restore( + x->impl(),prior->impl(),next->impl(),header()->impl()); + BOOST_RETHROW; + } + BOOST_CATCH_END + } + + bool modify_(node_type* x) + { + bool b; + BOOST_TRY{ + b=in_place(x,Category()); + } + BOOST_CATCH(...){ + erase_(x); + BOOST_RETHROW; + } + BOOST_CATCH_END + if(!b){ + ordered_index_node_impl::rebalance_for_erase( + x->impl(),header()->parent(),header()->left(),header()->right()); + BOOST_TRY{ + if(link2(key(x->value),x,Category())!=x){ + Super::erase_(x); + +#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE) + detach_iterators(x); +#endif + return false; + } + } + BOOST_CATCH(...){ + Super::erase_(x); + +#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE) + detach_iterators(x); +#endif + + BOOST_RETHROW; + } + BOOST_CATCH_END + } + + BOOST_TRY{ + if(!Super::modify_(x)){ + ordered_index_node_impl::rebalance_for_erase( + x->impl(),header()->parent(),header()->left(),header()->right()); + +#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE) + detach_iterators(x); +#endif + + return false; + } + else return true; + } + BOOST_CATCH(...){ + ordered_index_node_impl::rebalance_for_erase( + x->impl(),header()->parent(),header()->left(),header()->right()); + +#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE) + detach_iterators(x); +#endif + + BOOST_RETHROW; + } + BOOST_CATCH_END + } + +#if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING) + /* invariant stuff */ + + bool invariant_()const + { + if(size()==0||begin()==end()){ + if(size()!=0||begin()!=end()|| + header()->left()!=header()->impl()|| + header()->right()!=header()->impl())return false; + } + else{ + if((size_type)std::distance(begin(),end())!=size())return false; + + std::size_t len=ordered_index_node_impl::black_count( + leftmost()->impl(),root()->impl()); + for(const_iterator it=begin();it!=end();++it){ + node_type* x=it.get_node(); + node_type* left_x=node_type::from_impl(x->left()); + node_type* right_x=node_type::from_impl(x->right()); + + if(x->color()==red){ + if((left_x&&left_x->color()==red)|| + (right_x&&right_x->color()==red))return false; + } + if(left_x&&comp(key(x->value),key(left_x->value)))return false; + if(right_x&&comp(key(right_x->value),key(x->value)))return false; + if(!left_x&&!right_x&& + ordered_index_node_impl::black_count( + x->impl(),root()->impl())!=len) + return false; + } + + if(leftmost()->impl()!= + ordered_index_node_impl::minimum(root()->impl())) + return false; + if(rightmost()->impl()!= + ordered_index_node_impl::maximum(root()->impl())) + return false; + } + + return Super::invariant_(); + } + + + /* This forwarding function eases things for the boost::mem_fn construct + * in BOOST_MULTI_INDEX_ORD_INDEX_CHECK_INVARIANT. Actually, + * final_check_invariant is already an inherited member function of + * ordered_index. + */ + void check_invariant_()const{this->final_check_invariant_();} +#endif + +private: + node_type* header()const{return this->final_header();} + node_type* root()const{return node_type::from_impl(header()->parent());} + node_type* leftmost()const{return node_type::from_impl(header()->left());} + node_type* rightmost()const{return node_type::from_impl(header()->right());} + + void empty_initialize() + { + header()->color()=red; + /* used to distinguish header() from root, in iterator.operator++ */ + + header()->parent()=0; + header()->left()=header()->impl(); + header()->right()=header()->impl(); + } + + node_type* link4(key_param_type k,node_type* x,node_type* y,node_type* z) + { + if(x!=0||y==header()||comp(k,key(y->value))){ + y->left()=z->impl(); /* also makes leftmost()=z when y==header() */ + if (y==header()){ + header()->parent()=z->impl(); + header()->right()=z->impl(); + } + else if(y==leftmost()){ + header()->left()=z->impl(); + /* maintain leftmost() pointing to min node */ + } + } + else{ + y->right()=z->impl(); + if(y==rightmost()){ + header()->right()=z->impl(); + /* maintain rightmost() pointing to max node */ + } + } + z->parent()=y->impl(); + z->left()=0; + z->right()=0; + ordered_index_node_impl::rebalance(z->impl(),header()->parent()); + return z; + } + + node_type* link2(key_param_type k,node_type* z,ordered_unique_tag) + { + node_type* y=header(); + node_type* x=root(); + bool c=true; + while(x){ + y=x; + c=comp(k,key(x->value)); + x=node_type::from_impl(c?x->left():x->right()); + } + iterator j=make_iterator(y); + if(c){ + if(j==begin())return link4(k,x,y,z); + else --j; + } + + if(comp(key(*j),k))return link4(k,x,y,z); + else return j.get_node(); + } + + node_type* link2(key_param_type k,node_type* z,ordered_non_unique_tag) + { + node_type* y=header(); + node_type* x=root(); + while (x){ + y=x; + x=node_type::from_impl(comp(k,key(x->value))?x->left():x->right()); + } + return link4(k,x,y,z); + } + + node_type* link3( + key_param_type k,node_type* position,node_type* z,ordered_unique_tag) + { + if(position->impl()==header()->left()){ + if(size()>0&&comp(k,key(position->value))){ + return link4(k,position,position,z); + } + else return link2(k,z,ordered_unique_tag()); + } + else if(position==header()){ + if(comp(key(rightmost()->value),k)){ + return link4(k,0,rightmost(),z); + } + else return link2(k,z,ordered_unique_tag()); + } + else{ + node_type* before=position; + node_type::decrement(before); + if(comp(key(before->value),k)&&comp(k,key(position->value))){ + if(before->right()==0)return link4(k,0,before,z); + else return link4(k,position,position,z); + } + else return link2(k,z,ordered_unique_tag()); + } + } + + node_type* link3( + key_param_type k,node_type* position,node_type* z,ordered_non_unique_tag) + { + if(position->impl()==header()->left()){ + if(size()>0&&!comp(key(position->value),k)){ + return link4(k,position,position,z); + } + else return link2(k,z,ordered_non_unique_tag()); + } + else if(position==header()){ + if(!comp(k,key(rightmost()->value))){ + return link4(k,0,rightmost(),z); + } + else return link2(k,z,ordered_non_unique_tag()); + } + else{ + node_type* before=position; + node_type::decrement(before); + if (!comp(k,key(before->value))&&!comp(key(position->value),k)){ + if(before->right()==0)return link4(k,0,before,z); + else return link4(k,position,position,z); + } + else return link2(k,z,ordered_non_unique_tag()); + } + } + + bool in_place(node_type* x,ordered_unique_tag) + { + node_type* y=x; + node_type::decrement(y); + if(y!=header()&&!comp(key(y->value),key(x->value)))return false; + + y=x; + node_type::increment(y); + return y==header()||comp(key(x->value),key(y->value)); + } + + bool in_place(node_type* x,ordered_non_unique_tag) + { + node_type* y=x; + node_type::decrement(y); + if(y!=header()&&comp(key(x->value),key(y->value)))return false; + + y=x; + node_type::increment(y); + return y==header()||!comp(key(y->value),key(x->value)); + } + +#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE) + void detach_iterators(node_type* x) + { + iterator it=make_iterator(x); + safe_mode::detach_equivalent_iterators(it); + } +#endif + + template + const_iterator lower_range(LowerBounder lower)const + { + node_type* y=header(); + node_type* z=root(); + + while(z){ + if(lower(key(z->value))){ + y=z; + z=node_type::from_impl(z->left()); + } + else z=node_type::from_impl(z->right()); + } + + return make_iterator(y); + } + + const_iterator lower_range(unbounded_type)const + { + return begin(); + } + + template + const_iterator upper_range(UpperBounder upper)const + { + node_type* y=header(); + node_type* z=root(); + + while(z){ + if(!upper(key(z->value))){ + y=z; + z=node_type::from_impl(z->left()); + } + else z=node_type::from_impl(z->right()); + } + + return make_iterator(y); + } + + const_iterator upper_range(unbounded_type)const + { + return end(); + } + + key_from_value key; + key_compare comp; +}; + +/* comparison */ + +template< + typename KeyFromValue1,typename Compare1, + typename Super1,typename TagList1,typename Category1, + typename KeyFromValue2,typename Compare2, + typename Super2,typename TagList2,typename Category2 +> +bool operator==( + const ordered_index& x, + const ordered_index& y) +{ + return x.size()==y.size()&&std::equal(x.begin(),x.end(),y.begin()); +} + +template< + typename KeyFromValue1,typename Compare1, + typename Super1,typename TagList1,typename Category1, + typename KeyFromValue2,typename Compare2, + typename Super2,typename TagList2,typename Category2 +> +bool operator<( + const ordered_index& x, + const ordered_index& y) +{ + return std::lexicographical_compare(x.begin(),x.end(),y.begin(),y.end()); +} + +template< + typename KeyFromValue1,typename Compare1, + typename Super1,typename TagList1,typename Category1, + typename KeyFromValue2,typename Compare2, + typename Super2,typename TagList2,typename Category2 +> +bool operator!=( + const ordered_index& x, + const ordered_index& y) +{ + return !(x==y); +} + +template< + typename KeyFromValue1,typename Compare1, + typename Super1,typename TagList1,typename Category1, + typename KeyFromValue2,typename Compare2, + typename Super2,typename TagList2,typename Category2 +> +bool operator>( + const ordered_index& x, + const ordered_index& y) +{ + return y +bool operator>=( + const ordered_index& x, + const ordered_index& y) +{ + return !(x +bool operator<=( + const ordered_index& x, + const ordered_index& y) +{ + return !(x>y); +} + +/* specialized algorithms */ + +template< + typename KeyFromValue,typename Compare, + typename Super,typename TagList,typename Category +> +void swap( + ordered_index& x, + ordered_index& y) +{ + x.swap(y); +} + +} /* namespace multi_index::detail */ + +/* ordered_index specifiers */ + +template +struct ordered_unique +{ + typedef typename detail::ordered_index_args< + Arg1,Arg2,Arg3> index_args; + typedef typename index_args::tag_list_type tag_list_type; + typedef typename index_args::key_from_value_type key_from_value_type; + typedef typename index_args::compare_type compare_type; + + template + struct node_class + { + typedef detail::ordered_index_node type; + }; + + template + struct index_class + { + typedef detail::ordered_index< + key_from_value_type,compare_type, + Super,tag_list_type,detail::ordered_unique_tag> type; + }; +}; + +template +struct ordered_non_unique +{ + typedef detail::ordered_index_args< + Arg1,Arg2,Arg3> index_args; + typedef typename index_args::tag_list_type tag_list_type; + typedef typename index_args::key_from_value_type key_from_value_type; + typedef typename index_args::compare_type compare_type; + + template + struct node_class + { + typedef detail::ordered_index_node type; + }; + + template + struct index_class + { + typedef detail::ordered_index< + key_from_value_type,compare_type, + Super,tag_list_type,detail::ordered_non_unique_tag> type; + }; +}; + +} /* namespace multi_index */ + +} /* namespace boost */ + +#undef BOOST_MULTI_INDEX_ORD_INDEX_CHECK_INVARIANT + +#endif diff --git a/include/boost/multi_index/ordered_index_fwd.hpp b/include/boost/multi_index/ordered_index_fwd.hpp new file mode 100644 index 0000000..1856af8 --- /dev/null +++ b/include/boost/multi_index/ordered_index_fwd.hpp @@ -0,0 +1,112 @@ +/* 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. + */ + +#ifndef BOOST_MULTI_INDEX_ORDERED_INDEX_FWD_HPP +#define BOOST_MULTI_INDEX_ORDERED_INDEX_FWD_HPP + +#include + +namespace boost{ + +namespace multi_index{ + +namespace detail{ + +template< + typename KeyFromValue,typename Compare, + typename Super,typename TagList,typename Category +> +class index; + +template< + typename KeyFromValue1,typename Compare1, + typename Super1,typename TagList1,typename Category1, + typename KeyFromValue2,typename Compare2, + typename Super2,typename TagList2,typename Category2 +> +bool operator==( + const index& x, + const index& y); + +template< + typename KeyFromValue1,typename Compare1, + typename Super1,typename TagList1,typename Category1, + typename KeyFromValue2,typename Compare2, + typename Super2,typename TagList2,typename Category2 +> +bool operator<( + const index& x, + const index& y); + +template< + typename KeyFromValue1,typename Compare1, + typename Super1,typename TagList1,typename Category1, + typename KeyFromValue2,typename Compare2, + typename Super2,typename TagList2,typename Category2 +> +bool operator!=( + const index& x, + const index& y); + +template< + typename KeyFromValue1,typename Compare1, + typename Super1,typename TagList1,typename Category1, + typename KeyFromValue2,typename Compare2, + typename Super2,typename TagList2,typename Category2 +> +bool operator>( + const index& x, + const index& y); + +template< + typename KeyFromValue1,typename Compare1, + typename Super1,typename TagList1,typename Category1, + typename KeyFromValue2,typename Compare2, + typename Super2,typename TagList2,typename Category2 +> +bool operator>=( + const index& x, + const index& y); + +template< + typename KeyFromValue1,typename Compare1, + typename Super1,typename TagList1,typename Category1, + typename KeyFromValue2,typename Compare2, + typename Super2,typename TagList2,typename Category2 +> +bool operator<=( + const index& x, + const index& y); + +template< + typename KeyFromValue,typename Compare, + typename Super,typename TagList,typename Category +> +void swap( + index& x, + index& y); + +} /* namespace multi_index::detail */ + +/* index specifiers */ + +template< + typename Arg1,typename Arg2=detail::null_arg,typename Arg3=detail::null_arg +> +struct ordered_unique; + +template< + typename Arg1,typename Arg2=detail::null_arg,typename Arg3=detail::null_arg +> +struct ordered_non_unique; + +} /* namespace multi_index */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/multi_index/safe_mode_errors.hpp b/include/boost/multi_index/safe_mode_errors.hpp new file mode 100644 index 0000000..54bbdde --- /dev/null +++ b/include/boost/multi_index/safe_mode_errors.hpp @@ -0,0 +1,43 @@ +/* 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. + */ + +#ifndef BOOST_MULTI_INDEX_SAFE_MODE_ERRORS_HPP +#define BOOST_MULTI_INDEX_SAFE_MODE_ERRORS_HPP + +namespace boost{ + +namespace multi_index{ + +namespace safe_mode{ + +/* Error codes for Boost.MultiIndex safe mode. These go in a separate + * header so that the user can include it when redefining + * BOOST_MULTI_INDEX_SAFE_MODE_ASSERT prior to the inclusion of + * any other header of Boost.MultiIndex. + */ + +enum error_code +{ + invalid_iterator=0, + not_dereferenceable_iterator, + not_incrementable_iterator, + not_decrementable_iterator, + not_owner, + not_same_owner, + invalid_range, + inside_range, + same_container +}; + +} /* namespace multi_index::safe_mode */ + +} /* namespace multi_index */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/multi_index/sequenced_index.hpp b/include/boost/multi_index/sequenced_index.hpp new file mode 100644 index 0000000..7764434 --- /dev/null +++ b/include/boost/multi_index/sequenced_index.hpp @@ -0,0 +1,751 @@ +/* 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. + */ + +#ifndef BOOST_MULTI_INDEX_SEQUENCED_INDEX_HPP +#define BOOST_MULTI_INDEX_SEQUENCED_INDEX_HPP + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING) +#define BOOST_MULTI_INDEX_SEQ_INDEX_CHECK_INVARIANT \ + detail::scope_guard BOOST_JOIN(check_invariant_,__LINE__)= \ + detail::make_obj_guard(*this,&sequenced_index::check_invariant_); \ + BOOST_JOIN(check_invariant_,__LINE__).touch(); +#else +#define BOOST_MULTI_INDEX_SEQ_INDEX_CHECK_INVARIANT +#endif + +namespace boost{ + +namespace multi_index{ + +namespace detail{ + +/* sequenced_index adds a layer of sequenced indexing to a given Super */ + +template + +#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE) +#if BOOST_WORKAROUND(BOOST_MSVC,<1300) +class sequenced_index: + BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS Super, + public index_proxy > +#else +class sequenced_index: + BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS Super, + public safe_container > +#endif +#else +class sequenced_index: + BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS Super +#endif + +{ +protected: + typedef sequenced_index_node node_type; + +public: + /* types */ + + typedef typename node_type::value_type value_type; + typedef tuples::null_type ctor_args; + typedef typename Super::final_allocator_type allocator_type; + typedef typename allocator_type::reference reference; + typedef typename allocator_type::const_reference const_reference; + +#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE) +#if BOOST_WORKAROUND(BOOST_MSVC,<1300) + typedef index_iterator iterator; + typedef index_iterator const_iterator; +#else + typedef index_iterator iterator; + typedef index_iterator const_iterator; +#endif +#else + typedef index_iterator iterator; + typedef index_iterator const_iterator; +#endif + + 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 typename + boost::reverse_iterator reverse_iterator; + typedef typename + boost::reverse_iterator const_reverse_iterator; + typedef typename TagList::type tag_list; + +protected: + typedef typename Super::final_node_type final_node_type; + typedef tuples::cons< + ctor_args, + typename Super::ctor_args_list> ctor_args_list; + typedef typename mpl::push_front< + typename Super::index_type_list, + sequenced_index>::type index_type_list; + typedef typename mpl::push_front< + typename Super::iterator_type_list, + iterator>::type iterator_type_list; + typedef typename mpl::push_front< + typename Super::const_iterator_type_list, + const_iterator>::type const_iterator_type_list; + typedef typename Super::copy_map_type copy_map_type; + +private: +#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE) +#if BOOST_WORKAROUND(BOOST_MSVC,<1300) + typedef index_proxy > safe_super; +#else + typedef safe_container safe_super; +#endif +#endif + + typedef typename call_traits::param_type value_param_type; + +public: + + /* construct/copy/destroy + * Default and copy ctors are in the protected section as indices are + * not supposed to be created on their own. No range ctor either. + */ + + sequenced_index& operator=( + const sequenced_index& x) + { + this->final()=x.final(); + return *this; + } + + template + void assign(InputIterator first,InputIterator last) + { + BOOST_MULTI_INDEX_SEQ_INDEX_CHECK_INVARIANT; + clear(); + for(;first!=last;++first)push_back(*first); + } + + void assign(size_type n,value_param_type value) + { + BOOST_MULTI_INDEX_SEQ_INDEX_CHECK_INVARIANT; + clear(); + for(size_type i=0;ifinal().get_allocator(); + } + + /* iterators */ + + iterator begin() + {return make_iterator(node_type::from_impl(header()->next()));} + const_iterator begin()const + {return make_iterator(node_type::from_impl(header()->next()));} + iterator end(){return make_iterator(header());} + const_iterator end()const{return make_iterator(header());} + reverse_iterator rbegin(){return make_reverse_iterator(end());} + const_reverse_iterator rbegin()const{return make_reverse_iterator(end());} + reverse_iterator rend(){return make_reverse_iterator(begin());} + const_reverse_iterator rend()const{return make_reverse_iterator(begin());} + + /* capacity */ + + bool empty()const{return this->final_empty_();} + size_type size()const{return this->final_size_();} + size_type max_size()const{return this->final_max_size_();} + + void resize(size_type n,value_param_type x=value_type()) + { + BOOST_MULTI_INDEX_SEQ_INDEX_CHECK_INVARIANT; + if(n>size())insert(end(),n-size(),x); + else if(n push_front(value_param_type x) + {return insert(begin(),x);} + void pop_front(){erase(begin());} + std::pair push_back(value_param_type x) + {return insert(end(),x);} + void pop_back(){erase(--end());} + + std::pair insert(iterator position,value_param_type x) + { + BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position); + BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this); + BOOST_MULTI_INDEX_SEQ_INDEX_CHECK_INVARIANT; + std::pair p=this->final_insert_(x); + /* "this->" not required by std, but CW9.2 seems to need it */ + + if(p.second)relink(position.get_node(),p.first); + return std::pair(make_iterator(p.first),p.second); + } + + void insert(iterator position,size_type n,value_param_type x) + { + BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position); + BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this); + BOOST_MULTI_INDEX_SEQ_INDEX_CHECK_INVARIANT; + for(size_type i=0;i + void insert(iterator position,InputIterator first,InputIterator last) + { + BOOST_MULTI_INDEX_SEQ_INDEX_CHECK_INVARIANT; + for(;first!=last;++first)insert(position,*first); + } + + void erase(iterator position) + { + BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position); + BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(position); + BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this); + BOOST_MULTI_INDEX_SEQ_INDEX_CHECK_INVARIANT; + +#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE) + /* MSVC++ 6.0 optimizer on safe mode code chokes if this + * this is not added. Left it for all compilers as it does no + * harm. + */ + + position.detach(); +#endif + + final_erase_(static_cast(position.get_node())); + } + + void erase(iterator first,iterator last) + { + BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(first); + BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(last); + BOOST_MULTI_INDEX_CHECK_IS_OWNER(first,*this); + BOOST_MULTI_INDEX_CHECK_IS_OWNER(last,*this); + BOOST_MULTI_INDEX_CHECK_VALID_RANGE(first,last); + BOOST_MULTI_INDEX_SEQ_INDEX_CHECK_INVARIANT; + while(first!=last){ + erase(first++); + } + } + + bool replace(iterator position,value_param_type x) + { + BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position); + BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(position); + BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this); + BOOST_MULTI_INDEX_SEQ_INDEX_CHECK_INVARIANT; + return final_replace_( + x,static_cast(position.get_node())); + } + + template + bool modify(iterator position,Modifier mod) + { + BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position); + BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(position); + BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this); + BOOST_MULTI_INDEX_SEQ_INDEX_CHECK_INVARIANT; + +#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE) + /* MSVC++ 6.0 optimizer on safe mode code chokes if this + * this is not added. Left it for all compilers as it does no + * harm. + */ + + position.detach(); +#endif + + return final_modify_( + mod,static_cast(position.get_node())); + } + + void swap(sequenced_index& x) + { + BOOST_MULTI_INDEX_SEQ_INDEX_CHECK_INVARIANT; + final_swap_(x.final()); + } + + void clear() + { + BOOST_MULTI_INDEX_SEQ_INDEX_CHECK_INVARIANT; + erase(begin(),end()); + } + + /* list operations */ + + void splice(iterator position,sequenced_index& x) + { + BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position); + BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this); + BOOST_MULTI_INDEX_CHECK_DIFFERENT_CONTAINER(*this,x); + BOOST_MULTI_INDEX_SEQ_INDEX_CHECK_INVARIANT; + iterator first=x.begin(),last=x.end(); + while(first!=last){ + if(insert(position,*first).second)x.erase(first++); + else ++first; + } + } + + void splice(iterator position,sequenced_index& x,iterator i) + { + BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position); + BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this); + BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(i); + BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(i); + BOOST_MULTI_INDEX_CHECK_IS_OWNER(i,x); + BOOST_MULTI_INDEX_SEQ_INDEX_CHECK_INVARIANT; + if(x==*this){ + if(position!=i)relink(position.get_node(),i.get_node()); + } + else{ + if(insert(position,*i).second){ + +#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE) + /* MSVC++ 6.0 optimizer has a hard time with safe mode, and the following + * workaround is needed. Left it for all compilers as it does no + * harm. + */ + i.detach(); + x.erase(x.make_iterator(i.get_node())); +#else + x.erase(i); +#endif + + } + } + } + + void splice( + iterator position,sequenced_index& x, + iterator first,iterator last) + { + BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position); + BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this); + BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(first); + BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(last); + BOOST_MULTI_INDEX_CHECK_IS_OWNER(first,x); + BOOST_MULTI_INDEX_CHECK_IS_OWNER(last,x); + BOOST_MULTI_INDEX_CHECK_VALID_RANGE(first,last); + BOOST_MULTI_INDEX_SEQ_INDEX_CHECK_INVARIANT; + if(x==*this){ + BOOST_MULTI_INDEX_CHECK_OUTSIDE_RANGE(position,first,last); + if(position!=last)relink( + position.get_node(),first.get_node(),last.get_node()); + } + else{ + while(first!=last){ + if(insert(position,*first).second)x.erase(first++); + else ++first; + } + } + } + + void remove(value_param_type value) + { + sequenced_index_remove( + *this,std::bind2nd(std::equal_to(),value)); + } + + template + void remove_if(Predicate pred) + { + sequenced_index_remove(*this,pred); + } + + void unique() + { + sequenced_index_unique(*this,std::equal_to()); + } + + template + void unique(BinaryPredicate binary_pred) + { + sequenced_index_unique(*this,binary_pred); + } + + void merge(sequenced_index& x) + { + sequenced_index_merge(*this,x,std::less()); + } + + template + void merge(sequenced_index& x,Compare comp) + { + sequenced_index_merge(*this,x,comp); + } + + void sort() + { + BOOST_MULTI_INDEX_SEQ_INDEX_CHECK_INVARIANT; + sequenced_index_sort(header(),std::less()); + } + + template + void sort(Compare comp) + { + BOOST_MULTI_INDEX_SEQ_INDEX_CHECK_INVARIANT; + sequenced_index_sort(header(),comp); + } + + void reverse() + { + BOOST_MULTI_INDEX_SEQ_INDEX_CHECK_INVARIANT; + sequenced_index_node_impl::reverse(header()->impl()); + } + + /* relocate operations */ + + void relocate(iterator position,iterator i) + { + BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position); + BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this); + BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(i); + BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(i); + BOOST_MULTI_INDEX_CHECK_IS_OWNER(i,*this); + BOOST_MULTI_INDEX_SEQ_INDEX_CHECK_INVARIANT; + if(position!=i)relink(position.get_node(),i.get_node()); + } + + void relocate(iterator position,iterator first,iterator last) + { + BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position); + BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this); + BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(first); + BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(last); + BOOST_MULTI_INDEX_CHECK_IS_OWNER(first,*this); + BOOST_MULTI_INDEX_CHECK_IS_OWNER(last,*this); + BOOST_MULTI_INDEX_CHECK_VALID_RANGE(first,last); + BOOST_MULTI_INDEX_CHECK_OUTSIDE_RANGE(position,first,last); + BOOST_MULTI_INDEX_SEQ_INDEX_CHECK_INVARIANT; + if(position!=last)relink( + position.get_node(),first.get_node(),last.get_node()); + } + +BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS: + sequenced_index(const ctor_args_list& args_list,const allocator_type& al): + Super(args_list.get_tail(),al) + +#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)&&\ + BOOST_WORKAROUND(BOOST_MSVC,<1300) + ,safe_super(final_header()) +#endif + + { + header()->prior()=header()->next()=header()->impl(); + } + + sequenced_index(const sequenced_index& x): + Super(x) + +#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)&&\ + BOOST_WORKAROUND(BOOST_MSVC,<1300) + ,safe_super(final_header()) +#endif + + { + /* The actual copying takes place in subsequent call to copy_(). + */ + } + + ~sequenced_index() + { + /* the container is guaranteed to be empty by now */ + } + +#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE) + iterator make_iterator(node_type* node){return iterator(node,this);} + const_iterator make_iterator(node_type* node)const + {return const_iterator(node,const_cast(this));} +#else + iterator make_iterator(node_type* node){return iterator(node);} + const_iterator make_iterator(node_type* node)const + {return const_iterator(node);} +#endif + + void copy_(const sequenced_index& x,const copy_map_type& map) + { + node_type* org=x.header(); + node_type* cpy=header(); + do{ + node_type* next_org=node_type::from_impl(org->next()); + node_type* next_cpy=map.find(static_cast(next_org)); + cpy->next()=next_cpy->impl(); + next_cpy->prior()=cpy->impl(); + org=next_org; + cpy=next_cpy; + }while(org!=x.header()); + + Super::copy_(x,map); + } + + node_type* insert_(value_param_type v,node_type* x) + { + node_type* res=static_cast(Super::insert_(v,x)); + if(res==x)link(x); + return res; + } + + node_type* insert_(value_param_type v,node_type* position,node_type* x) + { + node_type* res=static_cast(Super::insert_(v,position,x)); + if(res==x)link(x); + return res; + } + + void erase_(node_type* x) + { + unlink(x); + Super::erase_(x); + +#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE) + detach_iterators(x); +#endif + } + + void swap_(sequenced_index& x) + { +#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE) + safe_super::swap(x); +#endif + + Super::swap_(x); + } + + bool replace_(value_param_type v,node_type* x) + { + return Super::replace_(v,x); + } + + bool modify_(node_type* x) + { + BOOST_TRY{ + if(!Super::modify_(x)){ + unlink(x); + +#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE) + detach_iterators(x); +#endif + + return false; + } + else return true; + } + BOOST_CATCH(...){ + unlink(x); + +#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE) + detach_iterators(x); +#endif + + BOOST_RETHROW; + } + BOOST_CATCH_END + + return true; + } + +#if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING) + /* invariant stuff */ + + bool invariant_()const + { + if(size()==0||begin()==end()){ + if(size()!=0||begin()!=end()|| + header()->next()!=header()->impl()|| + header()->prior()!=header()->impl())return false; + } + else{ + size_type s=0; + for(const_iterator it=begin();it!=end();++it,++s){ + if(it.get_node()->next()->prior()!=it.get_node()->impl())return false; + if(it.get_node()->prior()->next()!=it.get_node()->impl())return false; + } + if(s!=size())return false; + } + + return Super::invariant_(); + } + + /* This forwarding function eases things for the boost::mem_fn construct + * in BOOST_MULTI_INDEX_SEQ_INDEX_CHECK_INVARIANT. Actually, + * final_check_invariant is already an inherited member function of index. + */ + void check_invariant_()const{this->final_check_invariant_();} +#endif + +private: + node_type* header()const{return this->final_header();} + + void link(node_type* x) + { + sequenced_index_node_impl::link(x->impl(),header()->impl()); + }; + + static void unlink(node_type* x) + { + sequenced_index_node_impl::unlink(x->impl()); + } + + static void relink(node_type* position,node_type* x) + { + sequenced_index_node_impl::relink(position->impl(),x->impl()); + } + + static void relink(node_type* position,node_type* first,node_type* last) + { + sequenced_index_node_impl::relink( + position->impl(),first->impl(),last->impl()); + } + +#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE) + void detach_iterators(node_type* x) + { + iterator it=make_iterator(x); + safe_mode::detach_equivalent_iterators(it); + } +#endif +}; + +/* comparison */ + +template< + typename Super1,typename TagList1, + typename Super2,typename TagList2 +> +bool operator==( + const sequenced_index& x, + const sequenced_index& y) +{ + return x.size()==y.size()&&std::equal(x.begin(),x.end(),y.begin()); +} + +template< + typename Super1,typename TagList1, + typename Super2,typename TagList2 +> +bool operator<( + const sequenced_index& x, + const sequenced_index& y) +{ + return std::lexicographical_compare(x.begin(),x.end(),y.begin(),y.end()); +} + +template< + typename Super1,typename TagList1, + typename Super2,typename TagList2 +> +bool operator!=( + const sequenced_index& x, + const sequenced_index& y) +{ + return !(x==y); +} + +template< + typename Super1,typename TagList1, + typename Super2,typename TagList2 +> +bool operator>( + const sequenced_index& x, + const sequenced_index& y) +{ + return y +bool operator>=( + const sequenced_index& x, + const sequenced_index& y) +{ + return !(x +bool operator<=( + const sequenced_index& x, + const sequenced_index& y) +{ + return !(x>y); +} + +/* specialized algorithms */ + +template +void swap( + sequenced_index& x, + sequenced_index& y) +{ + x.swap(y); +} + +} /* namespace multi_index::detail */ + +/* sequenced index specifier */ + +template +struct sequenced +{ + BOOST_STATIC_ASSERT(detail::is_tag::value); + + template + struct node_class + { + typedef detail::sequenced_index_node type; + }; + + template + struct index_class + { + typedef detail::sequenced_index type; + }; +}; + +} /* namespace multi_index */ + +} /* namespace boost */ + +#undef BOOST_MULTI_INDEX_SEQ_INDEX_CHECK_INVARIANT + +#endif diff --git a/include/boost/multi_index/sequenced_index_fwd.hpp b/include/boost/multi_index/sequenced_index_fwd.hpp new file mode 100644 index 0000000..baee842 --- /dev/null +++ b/include/boost/multi_index/sequenced_index_fwd.hpp @@ -0,0 +1,87 @@ +/* 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. + */ + +#ifndef BOOST_MULTI_INDEX_SEQUENCED_INDEX_FWD_HPP +#define BOOST_MULTI_INDEX_SEQUENCED_INDEX_FWD_HPP + +#include + +namespace boost{ + +namespace multi_index{ + +namespace detail{ + +template +class sequenced_index; + +template< + typename Super1,typename TagList1, + typename Super2,typename TagList2 +> +bool operator==( + const sequenced_index& x, + const sequenced_index& y); + +template< + typename Super1,typename TagList1, + typename Super2,typename TagList2 +> +bool operator<( + const sequenced_index& x, + const sequenced_index& y); + +template< + typename Super1,typename TagList1, + typename Super2,typename TagList2 +> +bool operator!=( + const sequenced_index& x, + const sequenced_index& y); + +template< + typename Super1,typename TagList1, + typename Super2,typename TagList2 +> +bool operator>( + const sequenced_index& x, + const sequenced_index& y); + +template< + typename Super1,typename TagList1, + typename Super2,typename TagList2 +> +bool operator>=( + const sequenced_index& x, + const sequenced_index& y); + +template< + typename Super1,typename TagList1, + typename Super2,typename TagList2 +> +bool operator<=( + const sequenced_index& x, + const sequenced_index& y); + +template +void swap( + sequenced_index& x, + sequenced_index& y); + +} /* namespace multi_index::detail */ + +/* index specifiers */ + +template > +struct sequenced; + +} /* namespace multi_index */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/multi_index/tag.hpp b/include/boost/multi_index/tag.hpp new file mode 100644 index 0000000..f714a76 --- /dev/null +++ b/include/boost/multi_index/tag.hpp @@ -0,0 +1,79 @@ +/* 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. + */ + +#ifndef BOOST_MULTI_INDEX_TAG_HPP +#define BOOST_MULTI_INDEX_TAG_HPP + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include +#include +#include +#include +#include +#include + +/* An alias to mpl::vector used to hide MPL from the user. + * tag contains types used as tag names for indices in get() functions. + */ + +/* This user_definable macro limits the number of elements of a tag; + * useful for shortening resulting symbol names (MSVC++ 6.0, for instance, + * has problems coping with very long symbol names.) + */ + +#if !defined(BOOST_MULTI_INDEX_LIMIT_TAG_SIZE) +#if defined(BOOST_MSVC)&&(BOOST_MSVC<1300) +#define BOOST_MULTI_INDEX_LIMIT_TAG_SIZE 3 +#else +#define BOOST_MULTI_INDEX_LIMIT_TAG_SIZE BOOST_MPL_LIMIT_VECTOR_SIZE +#endif +#endif + +#if BOOST_MULTI_INDEX_LIMIT_TAG_SIZE +struct is_tag +{ + BOOST_STATIC_CONSTANT(bool,value=(is_base_and_derived::value)); +}; + +} /* namespace multi_index::detail */ + +template< + BOOST_PP_ENUM_BINARY_PARAMS( + BOOST_MULTI_INDEX_TAG_SIZE, + typename T, + =mpl::void_ BOOST_PP_INTERCEPT) +> +struct tag:private detail::tag_marker +{ + typedef mpl::vector type; + + BOOST_STATIC_ASSERT(detail::no_duplicate_tags::value); +}; + +} /* namespace multi_index */ + +} /* namespace boost */ + +#undef BOOST_MULTI_INDEX_TAG_SIZE + +#endif diff --git a/include/boost/multi_index_container.hpp b/include/boost/multi_index_container.hpp new file mode 100644 index 0000000..59e9376 --- /dev/null +++ b/include/boost/multi_index_container.hpp @@ -0,0 +1,864 @@ +/* Multiply indexed container. + * + * 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. + */ + +#ifndef BOOST_MULTI_INDEX_HPP +#define BOOST_MULTI_INDEX_HPP + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING) +#include +#define BOOST_MULTI_INDEX_CHECK_INVARIANT \ + detail::scope_guard BOOST_JOIN(check_invariant_,__LINE__)= \ + detail::make_obj_guard(*this,&multi_index_container::check_invariant_); \ + BOOST_JOIN(check_invariant_,__LINE__).touch(); +#else +#define BOOST_MULTI_INDEX_CHECK_INVARIANT +#endif + +namespace boost{ + +namespace multi_index{ + +template +class multi_index_container: + private base_from_member< + typename detail::allocator::rebind_to< + Allocator, + typename detail::multi_index_node_type< + Value,IndexSpecifierList,Allocator>::type + >::type>, + BOOST_MULTI_INDEX_PRIVATE_IF_MEMBER_TEMPLATE_FRIENDS detail::header_holder< + typename detail::multi_index_node_type< + Value,IndexSpecifierList,Allocator>::type, + multi_index_container >, + public detail::multi_index_base_type::type +{ +private: +#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) + template friend class detail::index_base; + template friend class detail::header_holder; + template friend class detail::converter; +#endif + + typedef typename detail::multi_index_base_type< + Value,IndexSpecifierList,Allocator>::type super; + typedef base_from_member< + typename detail::allocator::rebind_to< + Allocator, + typename super::node_type + >::type> bfm_allocator; + typedef detail::header_holder< + typename super::node_type, + multi_index_container> bfm_header; + +public: + /* All types are inherited from super, a few are explicitly + * brought forward here to save us some typename's. + */ + +#if defined(BOOST_MSVC) + typedef + detail::default_constructible_tuple_cons< + typename super::ctor_args_list> ctor_args_list; +#else + typedef typename super::ctor_args_list ctor_args_list; +#endif + + typedef typename IndexSpecifierList::type index_specifier_type_list; + typedef typename super::index_type_list index_type_list; + typedef typename super::iterator_type_list iterator_type_list; + typedef typename super::const_iterator_type_list const_iterator_type_list; + typedef typename super::value_type value_type; + typedef typename super::final_allocator_type allocator_type; + typedef typename super::iterator iterator; + typedef typename super::const_iterator const_iterator; + + BOOST_STATIC_ASSERT( + detail::no_duplicate_tags_in_index_list::value); + + /* global project() needs to see this publicly */ + + typedef typename super::node_type node_type; + + /* construct/copy/destroy */ + + explicit multi_index_container( + const ctor_args_list& args_list=ctor_args_list(), + const allocator_type& al=allocator_type()): + bfm_allocator(al), + super(args_list,bfm_allocator::member), + node_count(0) + { + BOOST_MULTI_INDEX_CHECK_INVARIANT; + } + + template + multi_index_container( + InputIterator first,InputIterator last, + const ctor_args_list& args_list=ctor_args_list(), + const allocator_type& al=allocator_type()): + bfm_allocator(al), + super(args_list,bfm_allocator::member), + node_count(0) + { + BOOST_MULTI_INDEX_CHECK_INVARIANT; + BOOST_TRY{ + iterator hint=super::end(); + for(;first!=last;++first){ + hint=super::make_iterator(insert_(*first,hint.get_node()).first); + } + } + BOOST_CATCH(...){ + clean_up(); + BOOST_RETHROW; + } + BOOST_CATCH_END + } + + multi_index_container( + const multi_index_container& x): + bfm_allocator(x.bfm_allocator::member), + super(x), + node_count(0) + { + BOOST_MULTI_INDEX_CHECK_INVARIANT; + copy_map_type map(bfm_allocator::member,x.size(),x.header(),header()); + for(const_iterator it=x.begin();it!=x.end();++it)map.clone(it.get_node()); + super::copy_(x,map); + map.release(); + node_count=x.size(); + } + + ~multi_index_container() + { + BOOST_MULTI_INDEX_CHECK_INVARIANT; + clean_up(); + } + + multi_index_container& operator=( + const multi_index_container& x) + { + BOOST_MULTI_INDEX_CHECK_INVARIANT; + multi_index_container tmp(x); + swap(tmp); + return *this; + } + + allocator_type get_allocator()const + { + return allocator_type(bfm_allocator::member); + } + + /* retrieval of indices by number */ + +#if !defined(BOOST_NO_MEMBER_TEMPLATES) + template + struct nth_index + { + BOOST_STATIC_ASSERT(N>=0&&N::type::value); + typedef typename mpl::at_c::type type; + }; + + template + typename nth_index::type& get(BOOST_EXPLICIT_TEMPLATE_NON_TYPE(int,N)) + { + BOOST_STATIC_ASSERT(N>=0&&N::type::value); + return *this; + } + + template + const typename nth_index::type& get( + BOOST_EXPLICIT_TEMPLATE_NON_TYPE(int,N))const + { + BOOST_STATIC_ASSERT(N>=0&&N::type::value); + return *this; + } +#endif + + /* retrieval of indices by tag */ + +#if !defined(BOOST_NO_MEMBER_TEMPLATES) + template + struct index + { + typedef typename mpl::find_if< + index_type_list, + detail::has_tag + >::type iter; + + BOOST_STATIC_CONSTANT( + bool,index_found=!(is_same >::value)); + BOOST_STATIC_ASSERT(index_found); + + typedef typename iter::type type; + }; + + template + typename index::type& get(BOOST_EXPLICIT_TEMPLATE_TYPE(Tag)) + { + return *this; + } + + template + const typename index::type& get( + BOOST_EXPLICIT_TEMPLATE_TYPE(Tag))const + { + return *this; + } +#endif + + /* projection of iterators by number */ + +#if !defined(BOOST_NO_MEMBER_TEMPLATES) + template + struct nth_index_iterator + { + typedef typename nth_index::type::iterator type; + }; + + template + struct nth_index_const_iterator + { + typedef typename nth_index::type::const_iterator type; + }; + + template + typename nth_index_iterator::type project( + IteratorType it + BOOST_APPEND_EXPLICIT_TEMPLATE_NON_TYPE(int,N)) + { + typedef typename nth_index::type index; + + BOOST_STATIC_ASSERT( + (mpl::contains::value)); + + BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(it); + BOOST_MULTI_INDEX_CHECK_IS_OWNER( + it,static_cast(*this)); + + return index::make_iterator(static_cast(it.get_node())); + } + + template + typename nth_index_const_iterator::type project( + IteratorType it + BOOST_APPEND_EXPLICIT_TEMPLATE_NON_TYPE(int,N))const + { + typedef typename nth_index::type index; + + BOOST_STATIC_ASSERT(( + mpl::contains::value|| + mpl::contains::value)); + + BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(it); + BOOST_MULTI_INDEX_CHECK_IS_OWNER( + it,static_cast(*this)); + return index::make_iterator(static_cast(it.get_node())); + } +#endif + + /* projection of iterators by tag */ + +#if !defined(BOOST_NO_MEMBER_TEMPLATES) + template + struct index_iterator + { + typedef typename index::type::iterator type; + }; + + template + struct index_const_iterator + { + typedef typename index::type::const_iterator type; + }; + + template + typename index_iterator::type project( + IteratorType it + BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE(Tag)) + { + typedef typename index::type index; + + BOOST_STATIC_ASSERT( + (mpl::contains::value)); + + BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(it); + BOOST_MULTI_INDEX_CHECK_IS_OWNER( + it,static_cast(*this)); + return index::make_iterator(static_cast(it.get_node())); + } + + template + typename index_const_iterator::type project( + IteratorType it + BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE(Tag))const + { + typedef typename index::type index; + + BOOST_STATIC_ASSERT(( + mpl::contains::value|| + mpl::contains::value)); + + BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(it); + BOOST_MULTI_INDEX_CHECK_IS_OWNER( + it,static_cast(*this)); + return index::make_iterator(static_cast(it.get_node())); + } +#endif + +BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS: + typedef typename super::copy_map_type copy_map_type; + + node_type* header()const + { + return bfm_header::member; + } + + node_type* allocate_node() + { + return detail::allocator::allocate(bfm_allocator::member,1); + } + + void deallocate_node(node_type* x) + { + detail::allocator::deallocate(bfm_allocator::member,x,1); + } + + bool empty_()const + { + return node_count==0; + } + + std::size_t size_()const + { + return node_count; + } + + std::size_t max_size_()const + { + return static_cast(-1); + } + + std::pair insert_(const Value& v) + { + node_type* x=allocate_node(); + BOOST_TRY{ + node_type* res=super::insert_(v,x); + if(res==x){ + ++node_count; + return std::pair(res,true); + } + else{ + deallocate_node(x); + return std::pair(res,false); + } + } + BOOST_CATCH(...){ + deallocate_node(x); + BOOST_RETHROW; + } + BOOST_CATCH_END + } + + std::pair insert_(const Value& v,node_type* position) + { + node_type* x=allocate_node(); + BOOST_TRY{ + node_type* res=super::insert_(v,position,x); + if(res==x){ + ++node_count; + return std::pair(res,true); + } + else{ + deallocate_node(x); + return std::pair(res,false); + } + } + BOOST_CATCH(...){ + deallocate_node(x); + BOOST_RETHROW; + } + BOOST_CATCH_END + } + + void erase_(node_type* x) + { + super::erase_(x); + deallocate_node(x); + --node_count; + } + + void swap_(multi_index_container& x) + { + std::swap(bfm_header::member,x.bfm_header::member); + super::swap_(x); + std::swap(node_count,x.node_count); + } + + bool replace_(const Value& k,node_type* x) + { + return super::replace_(k,x); + } + + template + bool modify_(Modifier mod,node_type* x) + { + mod(const_cast(x->value)); + + BOOST_TRY{ + if(!super::modify_(x)){ + deallocate_node(x); + --node_count; + return false; + } + else return true; + } + BOOST_CATCH(...){ + deallocate_node(x); + --node_count; + BOOST_RETHROW; + } + BOOST_CATCH_END + } + +#if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING) + /* invariant stuff */ + + bool invariant_()const + { + return super::invariant_(); + } + + void check_invariant_()const + { + BOOST_MULTI_INDEX_INVARIANT_ASSERT(invariant_()); + } +#endif + +private: + void clean_up() + { + for(iterator it=super::begin();it!=super::end();)erase_(it++.get_node()); + } + + std::size_t node_count; +}; + +/* retrieval of indices by number */ + +template +struct nth_index +{ + BOOST_STATIC_CONSTANT( + int, + M=mpl::size::type::value); + BOOST_STATIC_ASSERT(N>=0&&N::type type; +}; + +template +typename nth_index< + multi_index_container,N>::type& +get( + multi_index_container& m + BOOST_APPEND_EXPLICIT_TEMPLATE_NON_TYPE(int,N)) +{ + typedef multi_index_container< + Value,IndexSpecifierList,Allocator> multi_index_type; + typedef typename nth_index< + multi_index_container< + Value,IndexSpecifierList,Allocator>, + N + >::type index; + + BOOST_STATIC_ASSERT(N>=0&& + N< + mpl::size< + BOOST_DEDUCED_TYPENAME multi_index_type::index_type_list + >::type::value); + + return detail::converter::index(m); +} + +template +const typename nth_index< + multi_index_container,N>::type& +get( + const multi_index_container& m + BOOST_APPEND_EXPLICIT_TEMPLATE_NON_TYPE(int,N)) +{ + typedef multi_index_container< + Value,IndexSpecifierList,Allocator> multi_index_type; + typedef typename nth_index< + multi_index_container< + Value,IndexSpecifierList,Allocator>, + N + >::type index; + + BOOST_STATIC_ASSERT(N>=0&& + N< + mpl::size< + BOOST_DEDUCED_TYPENAME multi_index_type::index_type_list + >::type::value); + + return detail::converter::index(m); +} + +/* retrieval of indices by tag */ + +template +struct index +{ + typedef typename MultiIndexContainer::index_type_list index_type_list; + + typedef typename mpl::find_if< + index_type_list, + detail::has_tag + >::type iter; + + BOOST_STATIC_CONSTANT( + bool,index_found=!(is_same >::value)); + BOOST_STATIC_ASSERT(index_found); + + typedef typename iter::type type; +}; + +template< + typename Tag,typename Value,typename IndexSpecifierList,typename Allocator +> +typename index< + multi_index_container,Tag>::type& +get( + multi_index_container& m + BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE(Tag)) +{ + typedef multi_index_container< + Value,IndexSpecifierList,Allocator> multi_index_type; + typedef typename index< + multi_index_container< + Value,IndexSpecifierList,Allocator>, + Tag + >::type index; + + return detail::converter::index(m); +} + +template< + typename Tag,typename Value,typename IndexSpecifierList,typename Allocator +> +const typename index< + multi_index_container,Tag>::type& +get( + const multi_index_container& m + BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE(Tag)) +{ + typedef multi_index_container< + Value,IndexSpecifierList,Allocator> multi_index_type; + typedef typename index< + multi_index_container< + Value,IndexSpecifierList,Allocator>, + Tag + >::type index; + + return detail::converter::index(m); +} + +/* projection of iterators by number */ + +template +struct nth_index_iterator +{ + typedef typename detail::prevent_eti< + nth_index, + typename nth_index::type>::type::iterator type; +}; + +template +struct nth_index_const_iterator +{ + typedef typename detail::prevent_eti< + nth_index, + typename nth_index::type + >::type::const_iterator type; +}; + +template< + int N,typename IteratorType, + typename Value,typename IndexSpecifierList,typename Allocator> +typename nth_index_iterator< + multi_index_container,N>::type +project( + multi_index_container& m, + IteratorType it + BOOST_APPEND_EXPLICIT_TEMPLATE_NON_TYPE(int,N)) +{ + typedef multi_index_container< + Value,IndexSpecifierList,Allocator> multi_index_type; + typedef typename nth_index::type index; + +#if !defined(BOOST_MSVC)||!(BOOST_MSVC<1300) /* this ain't work in MSVC++ 6.0 */ + BOOST_STATIC_ASSERT(( + mpl::contains< + BOOST_DEDUCED_TYPENAME multi_index_type::iterator_type_list, + IteratorType>::value)); +#endif + + BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(it); + +#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE) + typedef detail::converter< + multi_index_type, + BOOST_DEDUCED_TYPENAME IteratorType::container_type> converter; + BOOST_MULTI_INDEX_CHECK_IS_OWNER(it,converter::index(m)); +#endif + + return detail::converter::iterator( + m,static_cast(it.get_node())); +} + +template< + int N,typename IteratorType, + typename Value,typename IndexSpecifierList,typename Allocator> +typename nth_index_const_iterator< + multi_index_container,N>::type +project( + const multi_index_container& m, + IteratorType it + BOOST_APPEND_EXPLICIT_TEMPLATE_NON_TYPE(int,N)) +{ + typedef multi_index_container< + Value,IndexSpecifierList,Allocator> multi_index_type; + typedef typename nth_index::type index; + +#if !defined(BOOST_MSVC)||!(BOOST_MSVC<1300) /* this ain't work in MSVC++ 6.0 */ + BOOST_STATIC_ASSERT(( + mpl::contains< + BOOST_DEDUCED_TYPENAME multi_index_type::iterator_type_list, + IteratorType>::value|| + mpl::contains< + BOOST_DEDUCED_TYPENAME multi_index_type::const_iterator_type_list, + IteratorType>::value)); +#endif + + BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(it); + +#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE) + typedef detail::converter< + multi_index_type, + BOOST_DEDUCED_TYPENAME IteratorType::container_type> converter; + BOOST_MULTI_INDEX_CHECK_IS_OWNER(it,converter::index(m)); +#endif + + return detail::converter::const_iterator( + m,static_cast(it.get_node())); +} + +/* projection of iterators by tag */ + +template +struct index_iterator +{ + typedef typename index::type::iterator type; +}; + +template +struct index_const_iterator +{ + typedef typename index::type::const_iterator type; +}; + +template< + typename Tag,typename IteratorType, + typename Value,typename IndexSpecifierList,typename Allocator> +typename index_iterator< + multi_index_container,Tag>::type +project( + multi_index_container& m, + IteratorType it + BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE(Tag)) +{ + typedef multi_index_container< + Value,IndexSpecifierList,Allocator> multi_index_type; + typedef typename index::type index; + +#if !defined(BOOST_MSVC)||!(BOOST_MSVC<1300) /* this ain't work in MSVC++ 6.0 */ + BOOST_STATIC_ASSERT(( + mpl::contains< + BOOST_DEDUCED_TYPENAME multi_index_type::iterator_type_list, + IteratorType>::value)); +#endif + + BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(it); + +#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE) + typedef detail::converter< + multi_index_type, + BOOST_DEDUCED_TYPENAME IteratorType::container_type> converter; + BOOST_MULTI_INDEX_CHECK_IS_OWNER(it,converter::index(m)); +#endif + + return detail::converter::iterator( + m,static_cast(it.get_node())); +} + +template< + typename Tag,typename IteratorType, + typename Value,typename IndexSpecifierList,typename Allocator> +typename index_const_iterator< + multi_index_container,Tag>::type +project( + const multi_index_container& m, + IteratorType it + BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE(Tag)) +{ + typedef multi_index_container< + Value,IndexSpecifierList,Allocator> multi_index_type; + typedef typename index::type index; + +#if !defined(BOOST_MSVC)||!(BOOST_MSVC<1300) /* this ain't work in MSVC++ 6.0 */ + BOOST_STATIC_ASSERT(( + mpl::contains< + BOOST_DEDUCED_TYPENAME multi_index_type::iterator_type_list, + IteratorType>::value|| + mpl::contains< + BOOST_DEDUCED_TYPENAME multi_index_type::const_iterator_type_list, + IteratorType>::value)); +#endif + + BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(it); + +#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE) + typedef detail::converter< + multi_index_type, + BOOST_DEDUCED_TYPENAME IteratorType::container_type> converter; + BOOST_MULTI_INDEX_CHECK_IS_OWNER(it,converter::index(m)); +#endif + + return detail::converter::const_iterator( + m,static_cast(it.get_node())); +} + +/* Comparison. Simple forward to first index. */ + +template< + typename Value1,typename IndexSpecifierList1,typename Allocator1, + typename Value2,typename IndexSpecifierList2,typename Allocator2 +> +bool operator==( + const multi_index_container& x, + const multi_index_container& y) +{ + return get<0>(x)==get<0>(y); +} + +template< + typename Value1,typename IndexSpecifierList1,typename Allocator1, + typename Value2,typename IndexSpecifierList2,typename Allocator2 +> +bool operator<( + const multi_index_container& x, + const multi_index_container& y) +{ + return get<0>(x)(y); +} + +template< + typename Value1,typename IndexSpecifierList1,typename Allocator1, + typename Value2,typename IndexSpecifierList2,typename Allocator2 +> +bool operator!=( + const multi_index_container& x, + const multi_index_container& y) +{ + return get<0>(x)!=get<0>(y); +} + +template< + typename Value1,typename IndexSpecifierList1,typename Allocator1, + typename Value2,typename IndexSpecifierList2,typename Allocator2 +> +bool operator>( + const multi_index_container& x, + const multi_index_container& y) +{ + return get<0>(x)>get<0>(y); +} + +template< + typename Value1,typename IndexSpecifierList1,typename Allocator1, + typename Value2,typename IndexSpecifierList2,typename Allocator2 +> +bool operator>=( + const multi_index_container& x, + const multi_index_container& y) +{ + return get<0>(x)>=get<0>(y); +} + +template< + typename Value1,typename IndexSpecifierList1,typename Allocator1, + typename Value2,typename IndexSpecifierList2,typename Allocator2 +> +bool operator<=( + const multi_index_container& x, + const multi_index_container& y) +{ + return get<0>(x)<=get<0>(y); +} + +/* specialized algorithms */ + +template +void swap( + multi_index_container& x, + multi_index_container& y) +{ + x.swap(y); +} + +} /* namespace multi_index */ + +/* Associated global functions are promoted to namespace boost, except + * comparison operators and swap, which are meant to be Koenig looked-up. + */ + +using multi_index::get; +using multi_index::project; + +} /* namespace boost */ + +#undef BOOST_MULTI_INDEX_CHECK_INVARIANT + +#endif diff --git a/include/boost/multi_index_container_fwd.hpp b/include/boost/multi_index_container_fwd.hpp new file mode 100644 index 0000000..1f1fc04 --- /dev/null +++ b/include/boost/multi_index_container_fwd.hpp @@ -0,0 +1,117 @@ +/* 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. + */ + +#ifndef BOOST_MULTI_INDEX_FWD_HPP +#define BOOST_MULTI_INDEX_FWD_HPP + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include +#include +#include + +namespace boost{ + +namespace multi_index{ + +/* Default value for IndexSpecifierList specifies a container + * equivalent to std::set. + */ + +template< + typename Value, + typename IndexSpecifierList=indexed_by > >, + typename Allocator=std::allocator > +class multi_index_container; + +template +struct nth_index; + +template +struct index; + +template +struct nth_index_iterator; + +template +struct nth_index_const_iterator; + +template +struct index_iterator; + +template +struct index_const_iterator; + +/* get and project functions not fwd declared due to problems + * with dependent typenames + */ + +template< + typename Value1,typename IndexSpecifierList1,typename Allocator1, + typename Value2,typename IndexSpecifierList2,typename Allocator2 +> +bool operator==( + const multi_index_container& x, + const multi_index_container& y); + +template< + typename Value1,typename IndexSpecifierList1,typename Allocator1, + typename Value2,typename IndexSpecifierList2,typename Allocator2 +> +bool operator<( + const multi_index_container& x, + const multi_index_container& y); + +template< + typename Value1,typename IndexSpecifierList1,typename Allocator1, + typename Value2,typename IndexSpecifierList2,typename Allocator2 +> +bool operator!=( + const multi_index_container& x, + const multi_index_container& y); + +template< + typename Value1,typename IndexSpecifierList1,typename Allocator1, + typename Value2,typename IndexSpecifierList2,typename Allocator2 +> +bool operator>( + const multi_index_container& x, + const multi_index_container& y); + +template< + typename Value1,typename IndexSpecifierList1,typename Allocator1, + typename Value2,typename IndexSpecifierList2,typename Allocator2 +> +bool operator>=( + const multi_index_container& x, + const multi_index_container& y); + +template< + typename Value1,typename IndexSpecifierList1,typename Allocator1, + typename Value2,typename IndexSpecifierList2,typename Allocator2 +> +bool operator<=( + const multi_index_container& x, + const multi_index_container& y); + +template +void swap( + multi_index_container& x, + multi_index_container& y); + +} /* namespace multi_index */ + +/* multi_index_container, being the main type of this library, is promoted to + * namespace boost. + */ + +using multi_index::multi_index_container; + +} /* namespace boost */ + +#endif diff --git a/index.html b/index.html new file mode 100644 index 0000000..664c02b --- /dev/null +++ b/index.html @@ -0,0 +1,16 @@ + + + + + + +Boost.MultiIndex Documentation + + + + +Automatic redirection failed, please go to +doc/index.html + + + diff --git a/perf/Jamfile b/perf/Jamfile new file mode 100644 index 0000000..c7fc945 --- /dev/null +++ b/perf/Jamfile @@ -0,0 +1,15 @@ +# Boost.MultiIndex performance tests 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/perf ; + +exe test_perf + : test_perf.cpp + : $(BOOST_ROOT) + : release + ; diff --git a/perf/test_perf.cpp b/perf/test_perf.cpp new file mode 100644 index 0000000..3e3dadc --- /dev/null +++ b/perf/test_perf.cpp @@ -0,0 +1,556 @@ +/* Boost.MultiIndex performance test. + * + * 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. + */ + +#include /* keep it first to prevent nasty warns in MSVC */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace boost::multi_index; + +/* Measurement harness by Andrew Koenig, extracted from companion code to + * Stroustrup, B.: "Wrapping C++ Member Function Calls", The C++ Report, + * June 2000, Vol 12/No 6. + * Original code retrievable at: http://www.research.att.com/~bs/wrap_code.cpp + */ + +// How many clock units does it take to interrogate the clock? +static double clock_overhead() +{ + clock_t k = clock(), start, limit; + + // Wait for the clock to tick + do start = clock(); + while (start == k); + + // interrogate the clock until it has advanced at least a second + // (for reasonable accuracy) + limit = start + CLOCKS_PER_SEC; + + unsigned long r = 0; + while ((k = clock()) < limit) + ++r; + + return double(k - start) / r; +} + +// We'd like the odds to be factor:1 that the result is +// within percent% of the median +const int factor = 10; +const int percent = 20; + +// Measure a function (object) factor*2 times, +// appending the measurements to the second argument +template +void measure_aux(F f, vector& mv) +{ + static double ovhd = clock_overhead(); + + // Ensure we don't reallocate in mid-measurement + mv.reserve(mv.size() + factor*2); + + // Wait for the clock to tick + clock_t k = clock(); + clock_t start; + + do start = clock(); + while (start == k); + + // Do 2*factor measurements + for (int i = 2*factor; i; --i) { + unsigned long count = 0, limit = 1, tcount = 0; + const clock_t clocklimit = start + CLOCKS_PER_SEC/100; + clock_t t; + + do { + while (count < limit) { + f(); + ++count; + } + limit *= 2; + ++tcount; + } while ((t = clock()) < clocklimit); + + // Wait for the clock to tick again; + clock_t t2; + do ++tcount; + while ((t2 = clock()) == t); + + // Append the measurement to the vector + mv.push_back(((t2 - start) - (tcount * ovhd)) / count); + + // Establish a new starting point + start = t2; + } +} + +// Returns the number of clock units per iteration +// With odds of factor:1, the measurement is within percent% of +// the value returned, which is also the median of all measurements. +template +double measure(F f) +{ + vector mv; + + int n = 0; // iteration counter + do { + ++n; + + // Try 2*factor measurements + measure_aux(f, mv); + assert(mv.size() == 2*n*factor); + + // Compute the median. We know the size is even, so we cheat. + sort(mv.begin(), mv.end()); + double median = (mv[n*factor] + mv[n*factor-1])/2; + + // If the extrema are within threshold of the median, we're done + if (mv[n] > (median * (100-percent))/100 && + mv[mv.size() - n - 1] < (median * (100+percent))/100) + return median; + + } while (mv.size() < factor * 200); + + // Give up! + clog << "Help!\n\n"; + exit(1); +} + +/* dereferencing compare predicate */ + +template +struct it_compare +{ + bool operator()(const Iterator& x,const Iterator& y)const{return comp(*x,*y);} + +private: + Compare comp; +}; + +/* list_wrapper and multiset_wrapper adapt std::lists and std::multisets + * to make them conform to a set-like insert interface which test + * routines do assume. + */ + +template +struct list_wrapper:List +{ + typedef typename List::value_type value_type; + typedef typename List::iterator iterator; + + pair insert(const value_type& v) + { + List::push_back(v); + return pair(--end(),true); + } +}; + +template +struct multiset_wrapper:Multiset +{ + typedef typename Multiset::value_type value_type; + typedef typename Multiset::iterator iterator; + + pair insert(const value_type& v) + { + return pair(Multiset::insert(v),true); + } +}; + +/* space comsumption of manual simulations is determined by checking + * the node sizes of the containers involved. This cannot be done in a + * portable manner, so node_size has to be written on a per stdlibrary + * basis. Add your own versions if necessary. + */ + +#if defined(BOOST_DINKUMWARE_STDLIB) + +template +size_t node_size(const Container&) +{ + return sizeof(*Container().begin()._Mynode()); +} + +#elif defined(__GLIBCPP__) + +template +size_t node_size(const Container&) +{ + typedef typename Container::iterator::_Link_type node_ptr; + node_ptr p=0; + return sizeof(*p); +} + +template +size_t node_size(const list&) +{ + return sizeof(typename list::iterator::_Node); +} + +template +size_t node_size(const list_wrapper&) +{ + return sizeof(typename List::iterator::_Node); +} + +#else + +/* default version returns 0 by convention */ + +template +size_t node_size(const Container&) +{ + return 0; +} + +#endif + +/* mono_container runs the tested routine on multi_index and manual + * simulations comprised of one standard container. + * bi_container and tri_container run the equivalent routine for manual + * compositions of two and three standard containers, respectively. + */ + +template +struct mono_container +{ + mono_container(int n_):n(n_){} + + void operator()() + { + typedef typename Container::iterator iterator; + + Container c; + + for(int i=0;i +struct bi_container +{ + bi_container(int n_):n(n_){} + + void operator()() + { + typedef typename Container1::iterator iterator1; + typedef typename Container2::iterator iterator2; + + Container1 c1; + Container2 c2; + + for(int i=0;i +struct tri_container +{ + tri_container(int n_):n(n_){} + + void operator()() + { + typedef typename Container1::iterator iterator1; + typedef typename Container2::iterator iterator2; + typedef typename Container3::iterator iterator3; + + Container1 c1; + Container2 c2; + Container3 c3; + + for(int i=0;i +void run_tests( + const char* title + BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE(IndexedTest) + BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE(ManualTest)) +{ + cout< +void compare_structures( + const char* title + BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE(IndexedType) + BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE(ManualType)) +{ + run_tests< + mono_container, + mono_container + >(title); +} + +template +void compare_structures2( + const char* title + BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE(IndexedType) + BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE(ManualType1) + BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE(ManualType2)) +{ + run_tests< + mono_container, + bi_container + >(title); +} + +template < + typename IndexedType, + typename ManualType1,typename ManualType2,typename ManualType3 +> +void compare_structures3( + const char* title + BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE(IndexedType) + BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE(ManualType1) + BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE(ManualType2) + BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE(ManualType3)) +{ + run_tests< + mono_container, + tri_container + >(title); +} + +int main() +{ + { + /* 1 ordered index */ + + typedef multi_index_container indexed_t; + typedef set manual_t; + indexed_t dummy; /* MSVC++ 6.0 chokes if indexed_t is not instantiated */ + + compare_structures( + "1 ordered index"); + } + { + /* 1 sequenced index */ + + typedef list_wrapper< + multi_index_container< + int, + indexed_by > + > + > indexed_t; + typedef list_wrapper > manual_t; + indexed_t dummy; /* MSVC++ 6.0 chokes if indexed_t is not instantiated */ + + compare_structures( + "1 sequenced index"); + } + { + /* 2 ordered indices */ + + typedef multi_index_container< + int, + indexed_by< + ordered_unique >, + ordered_non_unique > + > + > indexed_t; + typedef set manual_t1; + typedef multiset< + manual_t1::iterator, + it_compare< + manual_t1::iterator, + manual_t1::key_compare + > + > manual_t2; + indexed_t dummy; /* MSVC++ 6.0 chokes if indexed_t is not instantiated */ + + compare_structures2( + "2 ordered indices"); + } + { + /* 1 ordered index + 1 sequenced index */ + + typedef multi_index_container< + int, + indexed_by< + boost::multi_index::ordered_unique >, + sequenced<> + > + > indexed_t; + typedef list_wrapper< + list + > manual_t1; + typedef multiset< + manual_t1::iterator, + it_compare< + manual_t1::iterator, + std::less + > + > manual_t2; + indexed_t dummy; /* MSVC++ 6.0 chokes if indexed_t is not instantiated */ + + compare_structures2( + "1 ordered index + 1 sequenced index"); + } + { + /* 3 ordered indices */ + + typedef multi_index_container< + int, + indexed_by< + ordered_unique >, + ordered_non_unique >, + ordered_non_unique > + > + > indexed_t; + typedef set manual_t1; + typedef multiset_wrapper< + multiset< + manual_t1::iterator, + it_compare< + manual_t1::iterator, + manual_t1::key_compare + > + > + > manual_t2; + typedef multiset< + manual_t2::iterator, + it_compare< + manual_t2::iterator, + manual_t2::key_compare + > + > manual_t3; + indexed_t dummy; /* MSVC++ 6.0 chokes if indexed_t is not instantiated */ + + compare_structures3( + "3 ordered indices"); + } + { + /* 2 ordered indices + 1 sequenced index */ + + typedef multi_index_container< + int, + indexed_by< + ordered_unique >, + ordered_non_unique >, + sequenced<> + > + > indexed_t; + typedef list_wrapper< + list + > manual_t1; + typedef multiset_wrapper< + multiset< + manual_t1::iterator, + it_compare< + manual_t1::iterator, + std::less + > + > + > manual_t2; + typedef multiset< + manual_t2::iterator, + it_compare< + manual_t2::iterator, + manual_t2::key_compare + > + > manual_t3; + indexed_t dummy; /* MSVC++ 6.0 chokes if indexed_t is not instantiated */ + + compare_structures3( + "2 ordered indices + 1 sequenced index"); + } + + return 0; +} diff --git a/test/Jamfile b/test/Jamfile new file mode 100644 index 0000000..d038ac6 --- /dev/null +++ b/test/Jamfile @@ -0,0 +1,41 @@ +# Boost.MultiIndex tests 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/test ; + +# bring in rules for testing + +SEARCH on testing.jam = $(BOOST_BUILD_PATH) ; +include testing.jam ; + +# make tests run by default + +DEPENDS all : test ; + +{ + test-suite "multi_index" + : [ run test_basic_main.cpp test_basic.cpp ] + : [ run test_capacity_main.cpp test_capacity.cpp ] + : [ run test_comparison_main.cpp test_comparison.cpp ] + : [ run test_composite_key_main.cpp test_composite_key.cpp ] + : [ run test_conv_iterators_main.cpp test_conv_iterators.cpp ] + : [ run test_copy_assignment_main.cpp test_copy_assignment.cpp ] + : [ run test_iterators_main.cpp test_iterators.cpp ] + : [ run test_key_extractors_main.cpp test_key_extractors.cpp ] + : [ run test_list_ops_main.cpp test_list_ops.cpp ] + : [ run test_modifiers_main.cpp test_modifiers.cpp ] + : [ run test_mpl_ops_main.cpp test_mpl_ops.cpp ] + : [ run test_projection_main.cpp test_projection.cpp ] + : [ run test_range_main.cpp test_range.cpp ] + : [ run test_safe_mode_main.cpp test_safe_mode.cpp ] + : [ run test_set_ops_main.cpp test_set_ops.cpp ] + : [ run test_special_list_ops_main.cpp test_special_list_ops.cpp ] + : [ run test_special_set_ops_main.cpp test_special_set_ops.cpp ] + : [ run test_update_main.cpp test_update.cpp ] + ; +} diff --git a/test/employee.hpp b/test/employee.hpp new file mode 100644 index 0000000..8c57a74 --- /dev/null +++ b/test/employee.hpp @@ -0,0 +1,88 @@ +/* Used in Boost.MultiIndex tests. + * + * 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. + */ + +#ifndef BOOST_MULTI_INDEX_TEST_EMPLOYEE_HPP +#define BOOST_MULTI_INDEX_TEST_EMPLOYEE_HPP + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include +#include +#include +#include +#include +#include +#include + +struct employee +{ + int id; + std::string name; + int age; + + employee(int id_,std::string name_,int age_):id(id_),name(name_),age(age_){} + + bool operator==(const employee& x)const + { + return id==x.id&&name==x.name&&age==x.age; + } + + bool operator<(const employee& x)const + { + return id >, + boost::multi_index::ordered_non_unique< + boost::multi_index::tag, + BOOST_MULTI_INDEX_MEMBER(employee,std::string,name)>, + boost::multi_index::ordered_non_unique< + boost::multi_index::tag, + BOOST_MULTI_INDEX_MEMBER(employee,int,age)>, + boost::multi_index::sequenced< + boost::multi_index::tag > > > + employee_set; + +#if defined(BOOST_NO_MEMBER_TEMPLATES) +typedef boost::multi_index::nth_index< + employee_set,1>::type employee_set_by_name; +#else +typedef employee_set::nth_index<1>::type employee_set_by_name; +#endif + +typedef boost::multi_index::index< + employee_set,age>::type employee_set_by_age; +typedef boost::multi_index::index< + employee_set,as_inserted>::type employee_set_as_inserted; + +#endif diff --git a/test/pair_of_ints.hpp b/test/pair_of_ints.hpp new file mode 100644 index 0000000..388e4bd --- /dev/null +++ b/test/pair_of_ints.hpp @@ -0,0 +1,34 @@ +/* Used in Boost.MultiIndex tests. + * + * 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. + */ + +#ifndef BOOST_MULTI_INDEX_TEST_PAIR_OF_INTS_HPP +#define BOOST_MULTI_INDEX_TEST_PAIR_OF_INTS_HPP + +#include /* keep it first to prevent nasty warns in MSVC */ +#include + +typedef std::pair pair_of_ints; + +inline void increment_first(pair_of_ints& p) +{ + ++p.first; +} + +inline void increment_second(pair_of_ints& p) +{ + ++p.second; +} + +inline void increment_int(int& x) +{ + ++x; +} + +#endif diff --git a/test/pre_multi_index.hpp b/test/pre_multi_index.hpp new file mode 100644 index 0000000..2ddb4f8 --- /dev/null +++ b/test/pre_multi_index.hpp @@ -0,0 +1,31 @@ +/* Used in Boost.MultiIndex tests. + * + * 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. + */ + +#ifndef BOOST_MULTI_INDEX_TEST_PRE_MULTI_INDEX_HPP +#define BOOST_MULTI_INDEX_TEST_PRE_MULTI_INDEX_HPP + +#define BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING +#define BOOST_MULTI_INDEX_ENABLE_SAFE_MODE + +#include + +struct safe_mode_exception +{ + safe_mode_exception(boost::multi_index::safe_mode::error_code error_code_): + error_code(error_code_) + {} + + boost::multi_index::safe_mode::error_code error_code; +}; + +#define BOOST_MULTI_INDEX_SAFE_MODE_ASSERT(expr,error_code) \ +if(!(expr)){throw safe_mode_exception(error_code);} + +#endif diff --git a/test/test_all_main.cpp b/test/test_all_main.cpp new file mode 100644 index 0000000..b1017ee --- /dev/null +++ b/test/test_all_main.cpp @@ -0,0 +1,53 @@ +/* Boost.MultiIndex test suite. + * + * 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. + */ + +#include +#include "test_basic.hpp" +#include "test_capacity.hpp" +#include "test_comparison.hpp" +#include "test_composite_key.hpp" +#include "test_conv_iterators.hpp" +#include "test_copy_assignment.hpp" +#include "test_iterators.hpp" +#include "test_key_extractors.hpp" +#include "test_list_ops.hpp" +#include "test_modifiers.hpp" +#include "test_mpl_ops.hpp" +#include "test_projection.hpp" +#include "test_range.hpp" +#include "test_safe_mode.hpp" +#include "test_set_ops.hpp" +#include "test_special_list_ops.hpp" +#include "test_special_set_ops.hpp" +#include "test_update.hpp" + +int test_main(int,char *[]) +{ + test_basic(); + test_capacity(); + test_comparison(); + test_composite_key(); + test_conv_iterators(); + test_copy_assignment(); + test_iterators(); + test_key_extractors(); + test_list_ops(); + test_modifiers(); + test_mpl_ops(); + test_projection(); + test_range(); + test_safe_mode(); + test_set_ops(); + test_special_list_ops(); + test_special_set_ops(); + test_update(); + + return 0; +} diff --git a/test/test_basic.cpp b/test/test_basic.cpp new file mode 100644 index 0000000..62ca600 --- /dev/null +++ b/test/test_basic.cpp @@ -0,0 +1,90 @@ +/* Boost.MultiIndex basic test. + * + * 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. + */ + +#include "test_basic.hpp" + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include +#include "pre_multi_index.hpp" +#include "employee.hpp" +#include + +using namespace boost::multi_index; + +struct less_by_employee_name +{ + bool operator()(const employee& e1,const employee& e2)const + { + return e1.name v; + +#if defined(BOOST_NO_MEMBER_TEMPLATES) + employee_set_by_name& i1=get(es); +#else + employee_set_by_name& i1=es.get(); +#endif + + const employee_set_by_age& i2=get<2>(es); + employee_set_as_inserted& i3=get<3>(es); + + es.insert(employee(0,"Joe",31)); + i1.insert(employee(1,"Robert",27)); + es.insert(employee(2,"John",40)); + i3.push_back(employee(3,"Albert",20)); + es.insert(employee(4,"John",57)); + + v.push_back(employee(0,"Joe",31)); + v.push_back(employee(1,"Robert",27)); + v.push_back(employee(2,"John",40)); + v.push_back(employee(3,"Albert",20)); + v.push_back(employee(4,"John",57)); + + { + /* by insertion order */ + + BOOST_CHECK(std::equal(i3.begin(),i3.end(),v.begin())); + } + + { + /* by id */ + + std::sort(v.begin(),v.end()); + BOOST_CHECK(std::equal(es.begin(),es.end(),v.begin())); + } + + { + /* by name */ + + std::sort(v.begin(),v.end(),less_by_employee_name()); + BOOST_CHECK(std::equal(i1.begin(),i1.end(),v.begin())); + } + + { + /* by age */ + + std::sort(v.begin(),v.end(),less_by_employee_age()); + BOOST_CHECK(std::equal(i2.begin(),i2.end(),v.begin())); + } +} diff --git a/test/test_basic.hpp b/test/test_basic.hpp new file mode 100644 index 0000000..059f91f --- /dev/null +++ b/test/test_basic.hpp @@ -0,0 +1,11 @@ +/* Boost.MultiIndex basic test. + * + * 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. + */ + +void test_basic(); diff --git a/test/test_basic_main.cpp b/test/test_basic_main.cpp new file mode 100644 index 0000000..2b3a10e --- /dev/null +++ b/test/test_basic_main.cpp @@ -0,0 +1,18 @@ +/* Boost.MultiIndex basic test. + * + * 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. + */ + +#include +#include "test_basic.hpp" + +int test_main(int,char *[]) +{ + test_basic(); + return 0; +} diff --git a/test/test_capacity.cpp b/test/test_capacity.cpp new file mode 100644 index 0000000..9e0390a --- /dev/null +++ b/test/test_capacity.cpp @@ -0,0 +1,50 @@ +/* Boost.MultiIndex test for capacity memfuns. + * + * 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. + */ + +#include "test_capacity.hpp" + +#include /* keep it first to prevent nasty warns in MSVC */ +#include "pre_multi_index.hpp" +#include "employee.hpp" +#include + +using namespace boost::multi_index; + +void test_capacity() +{ + employee_set es; + + es.insert(employee(0,"Joe",31)); + es.insert(employee(1,"Robert",27)); + es.insert(employee(2,"John",40)); + es.insert(employee(3,"Albert",20)); + es.insert(employee(4,"John",57)); + + BOOST_CHECK(!es.empty()); + BOOST_CHECK(es.size()==5); + + es.erase(es.begin()); + BOOST_CHECK(get(es).size()==4); + + es.erase(es.begin()); + BOOST_CHECK(!get(es).empty()); + BOOST_CHECK(get(es).size()==3); + + multi_index_container > > ss; + + ss.resize(10); + BOOST_CHECK(ss.size()==10); + + ss.resize(20); + BOOST_CHECK(ss.size()==20); + + ss.resize(5); + BOOST_CHECK(ss.size()==5); +} diff --git a/test/test_capacity.hpp b/test/test_capacity.hpp new file mode 100644 index 0000000..77ef410 --- /dev/null +++ b/test/test_capacity.hpp @@ -0,0 +1,11 @@ +/* Boost.MultiIndex test for capacity memfuns. + * + * 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. + */ + +void test_capacity(); diff --git a/test/test_capacity_main.cpp b/test/test_capacity_main.cpp new file mode 100644 index 0000000..d81d4ce --- /dev/null +++ b/test/test_capacity_main.cpp @@ -0,0 +1,19 @@ +/* Boost.MultiIndex test for capacity memfuns. + * + * 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. + */ + +#include +#include "test_capacity.hpp" + +int test_main(int,char *[]) +{ + test_capacity(); + return 0; +} + diff --git a/test/test_comparison.cpp b/test/test_comparison.cpp new file mode 100644 index 0000000..ecbf886 --- /dev/null +++ b/test/test_comparison.cpp @@ -0,0 +1,84 @@ +/* Boost.MultiIndex test for comparison functions. + * + * 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. + */ + +#include "test_comparison.hpp" + +#include /* keep it first to prevent nasty warns in MSVC */ +#include "pre_multi_index.hpp" +#include "employee.hpp" +#include + +using namespace boost::multi_index; + +template +struct lookup_list{ + typedef multi_index_container< + Value, + indexed_by< + sequenced<>, + ordered_non_unique > + > + > type; +}; + +void test_comparison() +{ + employee_set es; + employee_set_by_name& i1=get<1>(es); + employee_set_as_inserted& i3=get<3>(es); + es.insert(employee(0,"Joe",31)); + es.insert(employee(1,"Robert",27)); + es.insert(employee(2,"John",40)); + es.insert(employee(3,"Albert",20)); + es.insert(employee(4,"John",57)); + + employee_set es2; + employee_set_by_name& i12=get(es2); + employee_set_as_inserted& i32=get<3>(es2); + es2.insert(employee(0,"Joe",31)); + es2.insert(employee(1,"Robert",27)); + es2.insert(employee(2,"John",40)); + es2.insert(employee(3,"Albert",20)); + + BOOST_CHECK(es==es&&es<=es&&es>=es&& + i12==i12&&i12<=i12&&i12>=i12&& + i32==i32&&i32<=i32&&i32>=i32); + BOOST_CHECK(es!=es2&&es2es2&&!(es<=es2)&&!(es2>=es)); + BOOST_CHECK(i1!=i12&&i12i12&&!(i1<=i12)&&!(i12>=i1)); + BOOST_CHECK(i3!=i32&&i32i32&&!(i3<=i32)&&!(i32>=i3)); + + lookup_list::type l1; + lookup_list::type l2; + lookup_list::type l3; + + l1.push_back(3); + l1.push_back(4); + l1.push_back(5); + l1.push_back(1); + l1.push_back(2); + + l2.push_back(char(3)); + l2.push_back(char(4)); + l2.push_back(char(5)); + l2.push_back(char(1)); + l2.push_back(char(2)); + + l3.push_back(long(3)); + l3.push_back(long(4)); + l3.push_back(long(5)); + l3.push_back(long(1)); + + BOOST_CHECK(l1==l2&&l1<=l2&&l1>=l2); + BOOST_CHECK( + get<1>(l1)==get<1>(l2)&&get<1>(l1)<=get<1>(l2)&&get<1>(l1)>=get<1>(l2)); + BOOST_CHECK(l1!=l3&&l3l3); + BOOST_CHECK( + get<1>(l1)!=get<1>(l3)&&get<1>(l1)(l3)&&get<1>(l3)>get<1>(l1)); +} diff --git a/test/test_comparison.hpp b/test/test_comparison.hpp new file mode 100644 index 0000000..3e68dd6 --- /dev/null +++ b/test/test_comparison.hpp @@ -0,0 +1,11 @@ +/* Boost.MultiIndex test for comparison functions. + * + * 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. + */ + +void test_comparison(); diff --git a/test/test_comparison_main.cpp b/test/test_comparison_main.cpp new file mode 100644 index 0000000..15b46bb --- /dev/null +++ b/test/test_comparison_main.cpp @@ -0,0 +1,19 @@ +/* Boost.MultiIndex test for comparison functions. + * + * 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. + */ + +#include +#include "test_comparison.hpp" + +int test_main(int,char *[]) +{ + test_comparison(); + return 0; +} + diff --git a/test/test_composite_key.cpp b/test/test_composite_key.cpp new file mode 100644 index 0000000..bab55d0 --- /dev/null +++ b/test/test_composite_key.cpp @@ -0,0 +1,448 @@ +/* Boost.MultiIndex test for composite_key. + * + * 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. + */ + +#include "test_composite_key.hpp" + +#include /* keep it first to prevent nasty warns in MSVC */ +#include "pre_multi_index.hpp" +#include +#include +#include +#include +#include + +using namespace boost::multi_index; +using namespace boost::tuples; + +template +struct is_composite_key_result +{ + typedef char yes; + struct no{char m[2];}; + + static no test(void *); + + template + static yes test(composite_key_result*); + + static T* make(); + + BOOST_STATIC_CONSTANT(bool,value=(sizeof(test(make()))==sizeof(yes))); +}; + +template +struct composite_key_result_length +{ + BOOST_STATIC_CONSTANT(int, + value=boost::tuples::length< + BOOST_DEDUCED_TYPENAME + CompositeKeyResult::composite_key_type::key_extractor_tuple + >::value); +}; + +template +struct composite_object_length +{ + typedef typename boost::mpl::if_c< + is_composite_key_result::value, + composite_key_result_length, + boost::tuples::length + >::type type; + + BOOST_STATIC_CONSTANT(int,value=type::value); +}; + +template +struct comparison_equal_length +{ + static bool is_less(const CompositeKeyResult& x,const T2& y) + { + composite_key_result_less lt; + composite_key_result_greater gt; + +#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) + std::less std_lt; + std::greater std_gt; +#endif + + return (x< y) && !(y< x)&& + !(x==y) && !(y==x)&& + (x!=y) && (y!=x)&& + !(x> y) && (y> x)&& + !(x>=y) && (y>=x)&& + (x<=y) && !(y<=x)&& + + lt(x,y) && !lt(y,x)&& + !gt(x,y) && gt(y,x) + +#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) + && + std_lt(x,y) && !std_lt(y,x)&& + !std_gt(x,y) && std_gt(y,x) +#endif + ; + } + + static bool is_greater(const CompositeKeyResult& x,const T2& y) + { + composite_key_result_less lt; + composite_key_result_greater gt; + +#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) + std::less std_lt; + std::greater std_gt; +#endif + + return !(x< y) && (y< x)&& + !(x==y) && !(y==x)&& + (x!=y) && (y!=x)&& + (x> y) && !(y> x)&& + (x>=y) && !(y>=x)&& + !(x<=y) && (y<=x)&& + + !lt(x,y) && lt(y,x)&& + gt(x,y) && !gt(y,x) + +#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) + && + !std_lt(x,y) && std_lt(y,x)&& + std_gt(x,y) && !std_gt(y,x) +#endif + ; + } + + static bool is_equiv(const CompositeKeyResult& x,const T2& y) + { + composite_key_result_less lt; + composite_key_result_greater gt; + +#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) + std::less std_lt; + std::greater std_gt; +#endif + + return !(x< y) && !(y< x)&& + (x==y) && (y==x)&& + !(x!=y) && !(y!=x)&& + !(x> y) && !(y> x)&& + (x>=y) && (y>=x)&& + (x<=y) && (y<=x)&& + + !lt(x,y) && !lt(y,x)&& + !gt(x,y) && !gt(y,x) + +#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) + && + !std_lt(x,y) && !std_lt(y,x)&& + !std_gt(x,y) && !std_gt(y,x) +#endif + ; + } +}; + +template +struct comparison_different_length +{ + static bool is_less(const CompositeKeyResult& x,const T2& y) + { + composite_key_result_less lt; + composite_key_result_greater gt; + +#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) + std::less std_lt; + std::greater std_gt; +#endif + + return (x< y) && !(y< x)&& + !(x> y) && (y> x)&& + !(x>=y) && (y>=x)&& + (x<=y) && !(y<=x)&& + + lt(x,y) && !lt(y,x)&& + !gt(x,y) && gt(y,x) + +#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) + && + std_lt(x,y) && !std_lt(y,x)&& + !std_gt(x,y) && std_gt(y,x) +#endif + ; + } + + static bool is_greater(const CompositeKeyResult& x,const T2& y) + { + composite_key_result_less lt; + composite_key_result_greater gt; + +#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) + std::less std_lt; + std::greater std_gt; +#endif + + return !(x< y) && (y< x)&& + (x> y) && !(y> x)&& + (x>=y) && !(y>=x)&& + !(x<=y) && (y<=x)&& + + !lt(x,y) && lt(y,x)&& + gt(x,y) && !gt(y,x) + +#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) + && + !std_lt(x,y) && std_lt(y,x)&& + std_gt(x,y) && !std_gt(y,x) +#endif + ; + } + + static bool is_equiv(const CompositeKeyResult& x,const T2& y) + { + composite_key_result_less lt; + composite_key_result_greater gt; + +#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) + std::less std_lt; + std::greater std_gt; +#endif + + return !(x< y) && !(y< x)&& + !(x> y) && !(y> x)&& + (x>=y) && (y>=x)&& + (x<=y) && (y<=x)&& + + !lt(x,y) && !lt(y,x)&& + !gt(x,y) && !gt(y,x) + +#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) + && + !std_lt(x,y) && !std_lt(y,x)&& + !std_gt(x,y) && !std_gt(y,x) +#endif + ; + } +}; + +template +struct comparison_helper: + boost::mpl::if_c< + composite_key_result_length::value== + composite_object_length::value, + comparison_equal_length, + comparison_different_length + >::type +{ +}; + +template +static bool is_less(const CompositeKeyResult& x,const T2& y) +{ + return comparison_helper::is_less(x,y); +} + +template +static bool is_greater(const CompositeKeyResult& x,const T2& y) +{ + return comparison_helper::is_greater(x,y); +} + +template +static bool is_equiv(const CompositeKeyResult& x,const T2& y) +{ + return comparison_helper::is_equiv(x,y); +} + +template +static bool is_less(const T1& x,const T2& y,const Compare& c) +{ + return c(x,y)&&!c(y,x); +} + +template +static bool is_greater(const T1& x,const T2& y,const Compare& c) +{ + return c(y,x)&&!c(x,y); +} + +template +static bool is_equiv(const T1& x,const T2& y,const Compare& c) +{ + return !c(x,y)&&!c(y,x); +} + +struct xyz +{ + xyz(int x_=0,int y_=0,int z_=0):x(x_),y(y_),z(z_){} + + int x; + int y; + int z; +}; + +void test_composite_key() +{ + typedef composite_key< + xyz, + BOOST_MULTI_INDEX_MEMBER(xyz,int,x), + BOOST_MULTI_INDEX_MEMBER(xyz,int,y), + BOOST_MULTI_INDEX_MEMBER(xyz,int,z) + > ckey_t1; + + typedef multi_index_container< + xyz, + indexed_by< + ordered_unique< + ckey_t1 +#if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) + ,composite_key_result_less +#endif + > + > + > indexed_t; + + indexed_t mc; + mc.insert(xyz(0,0,0)); + mc.insert(xyz(0,0,1)); + mc.insert(xyz(0,1,0)); + mc.insert(xyz(0,1,1)); + mc.insert(xyz(1,0,0)); + mc.insert(xyz(1,0,1)); + mc.insert(xyz(1,1,0)); + mc.insert(xyz(1,1,1)); + + BOOST_CHECK(mc.size()==8); + BOOST_CHECK( + std::distance( + mc.find(mc.key_extractor()(xyz(0,0,0))), + mc.find(mc.key_extractor()(xyz(1,0,0))))==4); + BOOST_CHECK( + std::distance( + mc.find(make_tuple(0,0,0)), + mc.find(make_tuple(1,0,0)))==4); + BOOST_CHECK( + std::distance( + mc.lower_bound(make_tuple(0,0)), + mc.upper_bound(make_tuple(1,0)))==6); + + ckey_t1 ck1; + ckey_t1 ck2(ck1); + ckey_t1 ck3( + boost::make_tuple( + BOOST_MULTI_INDEX_MEMBER(xyz,int,x)(), + BOOST_MULTI_INDEX_MEMBER(xyz,int,y)(), + BOOST_MULTI_INDEX_MEMBER(xyz,int,z)())); + ckey_t1 ck4(get<0>(ck1.key_extractors())); + + get<2>(ck4.key_extractors())= + get<2>(ck2.key_extractors()); + + BOOST_CHECK(is_equiv (ck1(xyz(0,0,0)),ck2(xyz(0,0,0)))); + BOOST_CHECK(is_less (ck1(xyz(0,0,1)),ck2(xyz(0,1,0)))); + BOOST_CHECK(is_greater(ck1(xyz(0,0,1)),ck2(xyz(0,0,0)))); + + BOOST_CHECK(is_equiv (ck1(xyz(0,0,0)),make_tuple(0))); + BOOST_CHECK(is_less (ck1(xyz(0,0,0)),make_tuple(1))); + BOOST_CHECK(is_greater(ck1(xyz(0,0,0)),make_tuple(-1))); + BOOST_CHECK(is_equiv (ck1(xyz(0,0,0)),make_tuple(0,0))); + BOOST_CHECK(is_less (ck1(xyz(0,0,0)),make_tuple(0,1))); + BOOST_CHECK(is_greater(ck1(xyz(0,0,0)),make_tuple(0,-1))); + BOOST_CHECK(is_equiv (ck1(xyz(0,0,0)),make_tuple(0,0,0))); + BOOST_CHECK(is_less (ck1(xyz(0,0,0)),make_tuple(0,0,1))); + BOOST_CHECK(is_greater(ck1(xyz(0,0,0)),make_tuple(0,0,-1))); + BOOST_CHECK(is_equiv (ck1(xyz(0,0,0)),make_tuple(0,0,0,1))); + + typedef composite_key_result_less ckey_comp_t1; + + ckey_comp_t1 cp1; + + BOOST_CHECK(is_equiv (ck1(xyz(0,0,0)),ck2(xyz(0,0,0)),cp1)); + BOOST_CHECK(is_less (ck1(xyz(0,0,1)),ck2(xyz(0,1,0)),cp1)); + BOOST_CHECK(is_greater(ck1(xyz(0,0,1)),ck2(xyz(0,0,0)),cp1)); + + BOOST_CHECK(is_equiv (ck1(xyz(0,0,0)),make_tuple(0),cp1)); + BOOST_CHECK(is_less (ck1(xyz(0,0,0)),make_tuple(1),cp1)); + BOOST_CHECK(is_greater(ck1(xyz(0,0,0)),make_tuple(-1),cp1)); + BOOST_CHECK(is_equiv (ck1(xyz(0,0,0)),make_tuple(0,0),cp1)); + BOOST_CHECK(is_less (ck1(xyz(0,0,0)),make_tuple(0,1),cp1)); + BOOST_CHECK(is_greater(ck1(xyz(0,0,0)),make_tuple(0,-1),cp1)); + BOOST_CHECK(is_equiv (ck1(xyz(0,0,0)),make_tuple(0,0,0),cp1)); + BOOST_CHECK(is_less (ck1(xyz(0,0,0)),make_tuple(0,0,1),cp1)); + BOOST_CHECK(is_greater(ck1(xyz(0,0,0)),make_tuple(0,0,-1),cp1)); + + typedef composite_key_result_greater ckey_comp_t2; + + ckey_comp_t2 cp2; + + BOOST_CHECK(is_equiv (ck1(xyz(0,0,0)),ck2(xyz(0,0,0)),cp2)); + BOOST_CHECK(is_greater(ck1(xyz(0,0,1)),ck2(xyz(0,1,0)),cp2)); + BOOST_CHECK(is_less (ck1(xyz(0,0,1)),ck2(xyz(0,0,0)),cp2)); + + BOOST_CHECK(is_equiv (ck1(xyz(0,0,0)),make_tuple(0),cp2)); + BOOST_CHECK(is_greater(ck1(xyz(0,0,0)),make_tuple(1),cp2)); + BOOST_CHECK(is_less (ck1(xyz(0,0,0)),make_tuple(-1),cp2)); + BOOST_CHECK(is_equiv (ck1(xyz(0,0,0)),make_tuple(0,0),cp2)); + BOOST_CHECK(is_greater(ck1(xyz(0,0,0)),make_tuple(0,1),cp2)); + BOOST_CHECK(is_less (ck1(xyz(0,0,0)),make_tuple(0,-1),cp2)); + BOOST_CHECK(is_equiv (ck1(xyz(0,0,0)),make_tuple(0,0,0),cp2)); + BOOST_CHECK(is_greater(ck1(xyz(0,0,0)),make_tuple(0,0,1),cp2)); + BOOST_CHECK(is_less (ck1(xyz(0,0,0)),make_tuple(0,0,-1),cp2)); + + typedef composite_key_compare< + std::less, + std::greater, /* order reversed */ + std::less + > ckey_comp_t3; + + ckey_comp_t3 cp3; + ckey_comp_t3 cp4(cp3); + ckey_comp_t3 cp5( + boost::make_tuple( + std::less(), + std::greater(), + std::less())); + ckey_comp_t3 cp6(get<0>(cp3.key_comps())); + + BOOST_CHECK(is_equiv (ck1(xyz(0,0,0)),ck2(xyz(0,0,0)),cp3)); + BOOST_CHECK(is_greater(ck1(xyz(0,0,1)),ck2(xyz(0,1,0)),cp3)); + BOOST_CHECK(is_greater(ck1(xyz(0,0,1)),ck2(xyz(0,0,0)),cp3)); + + BOOST_CHECK(is_equiv (ck1(xyz(0,0,0)),make_tuple(0),cp3)); + BOOST_CHECK(is_less (ck1(xyz(0,0,0)),make_tuple(1),cp3)); + BOOST_CHECK(is_greater(ck1(xyz(0,0,0)),make_tuple(-1),cp3)); + BOOST_CHECK(is_equiv (ck1(xyz(0,0,0)),make_tuple(0,0),cp3)); + BOOST_CHECK(is_less (ck1(xyz(0,0,0)),make_tuple(0,-1),cp3)); + BOOST_CHECK(is_greater(ck1(xyz(0,0,0)),make_tuple(0,1),cp3)); + BOOST_CHECK(is_equiv (ck1(xyz(0,0,0)),make_tuple(0,0,0),cp3)); + BOOST_CHECK(is_less (ck1(xyz(0,0,0)),make_tuple(0,0,1),cp3)); + BOOST_CHECK(is_greater(ck1(xyz(0,0,0)),make_tuple(0,0,-1),cp3)); + + typedef composite_key< + xyz, + BOOST_MULTI_INDEX_MEMBER(xyz,int,y), /* members reversed */ + BOOST_MULTI_INDEX_MEMBER(xyz,int,x) + > ckey_t2; + + ckey_t2 ck5; + + BOOST_CHECK(is_equiv (ck1(xyz(0,0,1)),ck5(xyz(0,0,0)))); + BOOST_CHECK(is_less (ck1(xyz(0,0,0)),ck5(xyz(-1,1,0)))); + BOOST_CHECK(is_greater(ck1(xyz(0,0,0)),ck5(xyz(1,-1,0)))); + + BOOST_CHECK(is_equiv (ck1(xyz(0,0,1)),ck5(xyz(0,0,0)),cp1)); + BOOST_CHECK(is_less (ck1(xyz(0,0,0)),ck5(xyz(-1,1,0)),cp1)); + BOOST_CHECK(is_greater(ck1(xyz(0,0,0)),ck5(xyz(1,-1,0)),cp1)); + + BOOST_CHECK(is_equiv (ck1(xyz(0,0,1)),ck5(xyz(0,0,0)),cp2)); + BOOST_CHECK(is_greater(ck1(xyz(0,0,0)),ck5(xyz(-1,1,0)),cp2)); + BOOST_CHECK(is_less (ck1(xyz(0,0,0)),ck5(xyz(1,-1,0)),cp2)); + + BOOST_CHECK(is_equiv (ck1(xyz(0,0,1)),ck5(xyz(0,0,0)),cp3)); + BOOST_CHECK(is_less (ck1(xyz(0,0,0)),ck5(xyz(-1,1,0)),cp3)); + BOOST_CHECK(is_greater(ck1(xyz(0,0,0)),ck5(xyz(1,-1,0)),cp3)); +} diff --git a/test/test_composite_key.hpp b/test/test_composite_key.hpp new file mode 100644 index 0000000..d7e4f54 --- /dev/null +++ b/test/test_composite_key.hpp @@ -0,0 +1,11 @@ +/* Boost.MultiIndex test for composite_key. + * + * 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. + */ + +void test_composite_key(); diff --git a/test/test_composite_key_main.cpp b/test/test_composite_key_main.cpp new file mode 100644 index 0000000..f803851 --- /dev/null +++ b/test/test_composite_key_main.cpp @@ -0,0 +1,18 @@ +/* Boost.MultiIndex test for composite_key. + * + * 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. + */ + +#include +#include "test_composite_key.hpp" + +int test_main(int,char *[]) +{ + test_composite_key(); + return 0; +} diff --git a/test/test_conv_iterators.cpp b/test/test_conv_iterators.cpp new file mode 100644 index 0000000..41a8805 --- /dev/null +++ b/test/test_conv_iterators.cpp @@ -0,0 +1,55 @@ +/* Boost.MultiIndex test for interconvertibilty between const and + * non-const iterators. + * + * 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. + */ + +#include "test_conv_iterators.hpp" + +#include /* keep it first to prevent nasty warns in MSVC */ +#include "pre_multi_index.hpp" +#include "employee.hpp" +#include + +using namespace boost::multi_index; + +void test_conv_iterators() +{ + employee_set es; + es.insert(employee(2,"John",40)); + + { + const employee_set& ces=es; + employee_set::iterator it=es.find(employee(2,"John",40)); + employee_set::const_iterator it1=es.find(employee(2,"John",40)); + employee_set::const_iterator it2=ces.find(employee(2,"John",40)); + + BOOST_CHECK(it==it1&&it1==it2&&it2==it); + BOOST_CHECK(*it==*it1&&*it1==*it2&&*it2==*it); + } + { + employee_set_by_name& i1=get<1>(es); + const employee_set_by_name& ci1=get<1>(es); + employee_set_by_name::iterator it=i1.find("John"); + employee_set_by_name::const_iterator it1=i1.find("John"); + employee_set_by_name::const_iterator it2=ci1.find("John"); + + BOOST_CHECK(it==it1&&it1==it2&&it2==it); + BOOST_CHECK(*it==*it1&&*it1==*it2&&*it2==*it); + } + { + employee_set_as_inserted& i3=get<3>(es); + const employee_set_as_inserted& ci3=get<3>(es); + employee_set_as_inserted::iterator it=i3.begin(); + employee_set_as_inserted::const_iterator it1=i3.begin(); + employee_set_as_inserted::const_iterator it2=ci3.begin(); + + BOOST_CHECK(it==it1&&it1==it2&&it2==it); + BOOST_CHECK(*it==*it1&&*it1==*it2&&*it2==*it); + } +} diff --git a/test/test_conv_iterators.hpp b/test/test_conv_iterators.hpp new file mode 100644 index 0000000..3fd81f4 --- /dev/null +++ b/test/test_conv_iterators.hpp @@ -0,0 +1,12 @@ +/* Boost.MultiIndex test for interconvertibilty between const and + * non-const iterators. + * + * 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. + */ + +void test_conv_iterators(); diff --git a/test/test_conv_iterators_main.cpp b/test/test_conv_iterators_main.cpp new file mode 100644 index 0000000..1586482 --- /dev/null +++ b/test/test_conv_iterators_main.cpp @@ -0,0 +1,21 @@ +/* Boost.MultiIndex test for interconvertibilty between const and + * non-const iterators. + * + * 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. + */ + +#include +#include "test_conv_iterators.hpp" + +int test_main(int,char *[]) +{ + test_conv_iterators(); + return 0; +} + + diff --git a/test/test_copy_assignment.cpp b/test/test_copy_assignment.cpp new file mode 100644 index 0000000..6628341 --- /dev/null +++ b/test/test_copy_assignment.cpp @@ -0,0 +1,91 @@ +/* Boost.MultiIndex test for copying and assignment. + * + * 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. + */ + +#include "test_copy_assignment.hpp" + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include +#include +#include +#include "pre_multi_index.hpp" +#include "employee.hpp" +#include + +using namespace boost::multi_index; + +void test_copy_assignment() +{ + employee_set es; + employee_set es2(es); + + BOOST_CHECK(es2.empty()); + + es2.insert(employee(0,"Joe",31)); + es2.insert(employee(1,"Robert",27)); + es2.insert(employee(2,"John",40)); + es2.insert(employee(2,"Aristotle",2387)); + es2.insert(employee(3,"Albert",20)); + es2.insert(employee(4,"John",57)); + + employee_set es3(es2); + + BOOST_CHECK(es2==es3); + BOOST_CHECK(get<2>(es2)==get<2>(es3)); + BOOST_CHECK(get<3>(es2)==get<3>(es3)); + + employee_set es4; + employee_set_by_age& i2=get(es4); + i2=get<2>(es2); + + BOOST_CHECK(i2==get<2>(es2)); + + employee_set es5; + employee_set_as_inserted& i3=get(es5); + i3=get<3>(es2); + + BOOST_CHECK(i3==get<3>(es2)); + + std::list l; + l.push_back(employee(3,"Anna",31)); + l.push_back(employee(1,"Rachel",27)); + l.push_back(employee(2,"Agatha",40)); + +#if BOOST_WORKAROUND(BOOST_MSVC,<1300) + employee_set es6; + es6.insert(l.begin(),l.end()); +#else + employee_set es6(l.begin(),l.end()); +#endif + + l.sort(); + + BOOST_CHECK(es6.size()==l.size()&& + std::equal(es6.begin(),es6.end(),l.begin())); + + multi_index_container > > ss; + + int a[]={0,1,2,3,4,5}; + std::size_t sa=sizeof(a)/sizeof(a[0]); + + ss.assign(&a[0],&a[sa]); + + BOOST_CHECK(ss.size()==ss.size()&&std::equal(ss.begin(),ss.end(),&a[0])); + + ss.assign(&a[0],&a[sa]); + + BOOST_CHECK(ss.size()==ss.size()&&std::equal(ss.begin(),ss.end(),&a[0])); + + ss.assign((std::size_t)18,37); + BOOST_CHECK(ss.size()==18&&std::accumulate(ss.begin(),ss.end(),0)==666); + + ss.assign((std::size_t)12,167); + BOOST_CHECK(ss.size()==12&&std::accumulate(ss.begin(),ss.end(),0)==2004); +} diff --git a/test/test_copy_assignment.hpp b/test/test_copy_assignment.hpp new file mode 100644 index 0000000..d38240f --- /dev/null +++ b/test/test_copy_assignment.hpp @@ -0,0 +1,11 @@ +/* Boost.MultiIndex test for copying and assignment. + * + * 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. + */ + +void test_copy_assignment(); diff --git a/test/test_copy_assignment_main.cpp b/test/test_copy_assignment_main.cpp new file mode 100644 index 0000000..cd4dbb8 --- /dev/null +++ b/test/test_copy_assignment_main.cpp @@ -0,0 +1,18 @@ +/* Boost.MultiIndex test for copying and assignment. + * + * 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. + */ + +#include +#include "test_copy_assignment.hpp" + +int test_main(int,char *[]) +{ + test_copy_assignment(); + return 0; +} diff --git a/test/test_iterators.cpp b/test/test_iterators.cpp new file mode 100644 index 0000000..088d75c --- /dev/null +++ b/test/test_iterators.cpp @@ -0,0 +1,87 @@ +/* Boost.MultiIndex test for iterators. + * + * 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. + */ + +#include "test_iterators.hpp" + +#include /* keep it first to prevent nasty warns in MSVC */ +#include "pre_multi_index.hpp" +#include "employee.hpp" +#include + +using namespace boost::multi_index; + +void test_iterators() +{ + employee_set es; + + es.insert(employee(0,"Joe",31)); + es.insert(employee(1,"Robert",27)); + es.insert(employee(2,"John",40)); + es.insert(employee(3,"Albert",20)); + es.insert(employee(4,"John",57)); + + { + int n=0; + for(employee_set::const_iterator it=es.begin();it!=es.end();++it){ + n+=it->id; + } + int m=0; + for(employee_set::reverse_iterator rit=es.rbegin();rit!=es.rend();++rit){ + m+=rit->id; + } + int p=0; + for(employee_set::const_iterator it2=es.end();it2!=es.begin();){ + --it2; + p+=it2->id; + } + int q=0; + for(employee_set::reverse_iterator rit2=es.rend();rit2!=es.rbegin();){ + --rit2; + q+=rit2->id; + } + + BOOST_CHECK(n==0+1+2+3+4&&n==m&&n==p&&n==q); + } + + { + int n=0; + employee_set_by_name& i1=get(es); + for(employee_set_by_name::iterator it=i1.begin();it!=i1.end();++it){ + n+=it->id; + } + int m=0; + const employee_set_by_age& i2=get<2>(es); + for(employee_set_by_age::const_reverse_iterator rit=i2.rbegin(); + rit!=i2.rend();++rit){ + m+=rit->id; + } + int p=0; + const employee_set_as_inserted& i3=get<3>(es); + for( + employee_set_as_inserted::const_reverse_iterator rit2=i3.rbegin(); + rit2!=i3.rend();++rit2){ + p+=rit2->id; + } + int q=0; + for(employee_set_by_name::iterator it2=i1.end();it2!=i1.begin();){ + --it2; + q+=it2->id; + } + int r=0; + for( + employee_set_as_inserted::const_iterator it3=i3.end(); + it3!=i3.begin();){ + --it3; + r+=it3->id; + } + + BOOST_CHECK(n==0+1+2+3+4&&n==m&&n==p&&n==q&&n==r); + } +} diff --git a/test/test_iterators.hpp b/test/test_iterators.hpp new file mode 100644 index 0000000..7e9d40c --- /dev/null +++ b/test/test_iterators.hpp @@ -0,0 +1,11 @@ +/* Boost.MultiIndex test for iterators. + * + * 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. + */ + +void test_iterators(); diff --git a/test/test_iterators_main.cpp b/test/test_iterators_main.cpp new file mode 100644 index 0000000..d3a1dad --- /dev/null +++ b/test/test_iterators_main.cpp @@ -0,0 +1,19 @@ +/* Boost.MultiIndex test for iterators. + * + * 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. + */ + +#include +#include "test_iterators.hpp" + +int test_main(int,char *[]) +{ + test_iterators(); + return 0; +} + diff --git a/test/test_key_extractors.cpp b/test/test_key_extractors.cpp new file mode 100644 index 0000000..a7d187c --- /dev/null +++ b/test/test_key_extractors.cpp @@ -0,0 +1,215 @@ +/* Boost.MultiIndex test for key extractors. + * + * 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. + */ + +#include "test_key_extractors.hpp" + +#include /* keep it first to prevent nasty warns in MSVC */ +#include "pre_multi_index.hpp" +#include +#include +#include +#include +#include +#include + +using namespace boost::multi_index; +using namespace boost::tuples; + +struct test_class +{ + int int_member; + const int int_cmember; + + bool bool_mem_fun_const()const{return true;} + bool bool_mem_fun(){return false;} + + test_class(int i=0):int_member(i),int_cmember(i){} + test_class(int i,int j):int_member(i),int_cmember(j){} + + bool operator<(const test_class& x)const + { + if(int_member idn; +typedef identity cidn; +typedef BOOST_MULTI_INDEX_MEMBER(test_class,int,int_member) key_m; +typedef BOOST_MULTI_INDEX_MEMBER(test_class,const int,int_member) ckey_m; +typedef BOOST_MULTI_INDEX_MEMBER(test_class,const int,int_cmember) key_cm; +typedef BOOST_MULTI_INDEX_CONST_MEM_FUN( + test_class,bool,bool_mem_fun_const) key_cmf; +typedef BOOST_MULTI_INDEX_MEM_FUN(test_class,bool,bool_mem_fun) key_mf; +typedef composite_key< + test_class, + idn, + key_m, + key_cm, + key_cmf + > compkey; +typedef composite_key< + test_class, + cidn, + ckey_m + > ccompkey; +typedef composite_key< + boost::reference_wrapper, + key_mf + > ccompw_key; + +void test_key_extractors() +{ + idn id; + cidn cid; + key_m k_m; + ckey_m ck_m; + key_cm k_cm; + key_cmf k_cmf; + key_mf k_mf; + compkey cmpk; + ccompkey ccmpk; + ccompw_key ccmpk_w; + + test_class t; + const test_class& ctr=t; + + test_class* tp=&t; + const test_class* ctp=&t; + + test_class** tpp=&tp; + const test_class** ctpp=&ctp; + + std::auto_ptr tap(new test_class*(tp)); + std::auto_ptr ctap(new const test_class*(ctp)); + + boost::reference_wrapper tw(t); + boost::reference_wrapper ctw(t); + + id(t).int_member=0; + BOOST_CHECK(id(t).int_member==0); + BOOST_CHECK(cid(t).int_member==0); + BOOST_CHECK(k_m(t)==0); + BOOST_CHECK(ck_m(t)==0); + BOOST_CHECK(cmpk(t)==make_tuple(test_class(0,0),0,0,true)); + BOOST_CHECK(ccmpk(t)==make_tuple(test_class(0,0),0)); + BOOST_CHECK(id(ctr).int_member==0); + BOOST_CHECK(cid(ctr).int_member==0); + BOOST_CHECK(k_m(ctr)==0); + BOOST_CHECK(ck_m(ctr)==0); + BOOST_CHECK(cmpk(ctr)==make_tuple(test_class(0,0),0,0,true)); + BOOST_CHECK(ccmpk(ctr)==make_tuple(test_class(0,0),0)); + + k_m(t)=1; + BOOST_CHECK(id(tp).int_member==1); + BOOST_CHECK(cid(tp).int_member==1); + BOOST_CHECK(k_m(tp)==1); + BOOST_CHECK(ck_m(tp)==1); + BOOST_CHECK(cmpk(tp)==make_tuple(test_class(1,0),1,0,true)); + BOOST_CHECK(ccmpk(tp)==make_tuple(test_class(1,0),1)); + BOOST_CHECK(cid(ctp).int_member==1); + BOOST_CHECK(ck_m(ctp)==1); + BOOST_CHECK(cmpk(ctp)==make_tuple(test_class(1,0),1,0,true)); + BOOST_CHECK(ccmpk(ctp)==make_tuple(test_class(1,0),1)); + + k_m(tp)=2; + BOOST_CHECK(id(tpp).int_member==2); + BOOST_CHECK(cid(tpp).int_member==2); + BOOST_CHECK(k_m(tpp)==2); + BOOST_CHECK(ck_m(tpp)==2); + BOOST_CHECK(cmpk(tpp)==make_tuple(test_class(2,0),2,0,true)); + BOOST_CHECK(ccmpk(tpp)==make_tuple(test_class(2,0),2)); + BOOST_CHECK(cid(ctpp).int_member==2); + BOOST_CHECK(ck_m(ctpp)==2); + BOOST_CHECK(cmpk(ctpp)==make_tuple(test_class(2,0),2,0,true)); + BOOST_CHECK(ccmpk(ctpp)==make_tuple(test_class(2,0),2)); + + k_m(tpp)=3; + BOOST_CHECK(id(tap).int_member==3); + BOOST_CHECK(cid(tap).int_member==3); + BOOST_CHECK(k_m(tap)==3); + BOOST_CHECK(ck_m(tap)==3); + BOOST_CHECK(cmpk(tap)==make_tuple(test_class(3,0),3,0,true)); + BOOST_CHECK(ccmpk(tap)==make_tuple(test_class(3,0),3)); + BOOST_CHECK(cid(ctap).int_member==3); + BOOST_CHECK(ck_m(ctap)==3); + BOOST_CHECK(cmpk(ctap)==make_tuple(test_class(3,0),3,0,true)); + BOOST_CHECK(ccmpk(ctap)==make_tuple(test_class(3,0),3)); + + k_m(tap)=4; + BOOST_CHECK(id(tw).int_member==4); + BOOST_CHECK(cid(tw).int_member==4); + BOOST_CHECK(k_m(tw)==4); + BOOST_CHECK(ck_m(tw)==4); + BOOST_CHECK(cmpk(tw)==make_tuple(test_class(4,0),4,0,true)); + BOOST_CHECK(ccmpk(tw)==make_tuple(test_class(4,0),4)); + + k_m(tw)=5; + BOOST_CHECK(id(ctw).int_member==5); + BOOST_CHECK(cid(ctw).int_member==5); + BOOST_CHECK(k_m(ctw)==5); + BOOST_CHECK(ck_m(ctw)==5); + BOOST_CHECK(cmpk(ctw)==make_tuple(test_class(5,0),5,0,true)); + BOOST_CHECK(ccmpk(ctw)==make_tuple(test_class(5,0),5)); + + BOOST_CHECK(k_cm(t)==0); + + BOOST_CHECK(k_cm(tp)==0); + BOOST_CHECK(k_cm(ctp)==0); + BOOST_CHECK(k_cm(tpp)==0); + BOOST_CHECK(k_cm(ctpp)==0); + BOOST_CHECK(k_cm(tap)==0); + BOOST_CHECK(k_cm(ctap)==0); + + BOOST_CHECK(k_cm(tw)==0); + BOOST_CHECK(k_cm(ctw)==0); + + BOOST_CHECK(k_cmf(t)); + + BOOST_CHECK(k_cmf(tp)); + BOOST_CHECK(k_cmf(ctp)); + BOOST_CHECK(k_cmf(tpp)); + BOOST_CHECK(k_cmf(ctpp)); + BOOST_CHECK(k_cmf(tap)); + BOOST_CHECK(k_cmf(ctap)); + + BOOST_CHECK(k_cmf(tw)); + BOOST_CHECK(k_cmf(ctw)); + + BOOST_CHECK(!k_mf(t)); + + BOOST_CHECK(!k_mf(tp)); + BOOST_CHECK(!k_mf(tpp)); + BOOST_CHECK(!k_mf(tap)); + BOOST_CHECK(!k_mf(tw)); + BOOST_CHECK(ccmpk_w(tw)==make_tuple(false)); + + std::list tl; + for(int i=0;i<20;++i)tl.push_back(test_class(i)); + + int j=0; + for(std::list::iterator it=tl.begin();it!=tl.end();++it){ + BOOST_CHECK(k_m(it)==j); + BOOST_CHECK(k_cm(it)==j); + BOOST_CHECK(k_cmf(it)); + BOOST_CHECK(!k_mf(it)); + BOOST_CHECK(cmpk(it)==make_tuple(test_class(j),j,j,true)); + BOOST_CHECK(ccmpk(it)==make_tuple(test_class(j),j)); + ++j; + } +} diff --git a/test/test_key_extractors.hpp b/test/test_key_extractors.hpp new file mode 100644 index 0000000..ef573ac --- /dev/null +++ b/test/test_key_extractors.hpp @@ -0,0 +1,11 @@ +/* Boost.MultiIndex test for key extractors. + * + * 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. + */ + +void test_key_extractors(); diff --git a/test/test_key_extractors_main.cpp b/test/test_key_extractors_main.cpp new file mode 100644 index 0000000..b191481 --- /dev/null +++ b/test/test_key_extractors_main.cpp @@ -0,0 +1,18 @@ +/* Boost.MultiIndex test for key extractors. + * + * 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. + */ + +#include +#include "test_key_extractors.hpp" + +int test_main(int,char *[]) +{ + test_key_extractors(); + return 0; +} diff --git a/test/test_list_ops.cpp b/test/test_list_ops.cpp new file mode 100644 index 0000000..3e00786 --- /dev/null +++ b/test/test_list_ops.cpp @@ -0,0 +1,184 @@ +/* Boost.MultiIndex test for standard list operations. + * + * 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. + */ + +#include "test_list_ops.hpp" + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include +#include "pre_multi_index.hpp" +#include +#include +#include +#include +#include + +using namespace boost::multi_index; + +#undef _ +#define _ , + +#undef CHECK_EQUAL +#define CHECK_EQUAL(p,check_range) \ +{\ + int v[]=check_range;\ + std::size_t size_v=sizeof(v)/sizeof(int);\ + BOOST_CHECK(std::size_t(std::distance((p).begin(),(p).end()))==size_v);\ + BOOST_CHECK(std::equal((p).begin(),(p).end(),v));\ +} + +#undef CHECK_VOID_RANGE +#define CHECK_VOID_RANGE(p) BOOST_CHECK((p).first==(p).second) + +struct is_even +{ + bool operator()(int x)const{return x%2==0;} +}; + +template +struct same_integral_div +{ + bool operator()(int x,int y)const{return (x/m)==(y/m);} +}; + +template +bool is_sorted( + const Container& c,const Compare& comp=Compare()) +{ + if(c.empty())return true; + + typedef typename Container::const_iterator const_iterator; + for(const_iterator it(c.begin());;){ + const_iterator it2=it; + ++it2; + if(it2==c.end())return true; + if(comp(*it2,*it))return false; + it=it2; + } +} + +void test_list_ops() +{ + typedef multi_index_container< + int, + indexed_by< + ordered_unique >, + sequenced<> + > + > sequenced_set; + typedef nth_index::type sequenced_index; + + sequenced_set ss,ss2; + sequenced_index &si=get<1>(ss),&si2=get<1>(ss2); + + si.push_front(0); /* 0 */ + si.push_front(4); /* 40 */ + ss.insert(2); /* 402 */ + ss.insert(5); /* 4025 */ + si.push_front(3); /* 34025 */ + si.push_back(6); /* 340256 */ + si.push_back(1); /* 3402561 */ + si.insert(project<1>(ss,ss.find(2)),8); /* 34082561 */ + si2=si; + + CHECK_EQUAL(si,{3 _ 4 _ 0 _ 8 _ 2 _ 5 _ 6 _ 1}); + + si.remove(8); + CHECK_EQUAL(si,{3 _ 4 _ 0 _ 2 _ 5 _ 6 _ 1}); + + si.remove_if(is_even()); + + CHECK_EQUAL(si,{3 _ 5 _ 1}); + + si.splice(si.end(),si2); + CHECK_EQUAL(si,{3 _ 5 _ 1 _ 4 _ 0 _ 8 _ 2 _ 6}); + CHECK_EQUAL(si2,{3 _ 5 _ 1}); + + si.splice(project<1>(ss,ss.find(4)),si,project<1>(ss,ss.find(8))); + CHECK_EQUAL(si,{3 _ 5 _ 1 _ 8 _ 4 _ 0 _ 2 _ 6}); + si2.clear(); + si2.splice(si2.begin(),si,si.begin()); + + si.splice(si.end(),si2,si2.begin()); + CHECK_EQUAL(si,{5 _ 1 _ 8 _ 4 _ 0 _ 2 _ 6 _ 3}); + BOOST_CHECK(si2.empty()); + + si2.splice(si2.end(),si,project<1>(ss,ss.find(0)),project<1>(ss,ss.find(6))); + CHECK_EQUAL(si,{5 _ 1 _ 8 _ 4 _ 6 _ 3}); + CHECK_EQUAL(si2,{0 _ 2}); + + si.splice(si.begin(),si,si.begin(),si.begin()); + CHECK_EQUAL(si,{5 _ 1 _ 8 _ 4 _ 6 _ 3}); + + si.splice(project<1>(ss,ss.find(8)),si,project<1>(ss,ss.find(4)),si.end()); + CHECK_EQUAL(si,{5 _ 1 _ 4 _ 6 _ 3 _ 8}); + + si.sort(); + si2.sort(); + BOOST_CHECK(is_sorted(si,std::less())); + BOOST_CHECK(is_sorted(si2,std::less())); + + si.merge(si2); + BOOST_CHECK(is_sorted(si,std::less())); + BOOST_CHECK(si2.empty()); + + { + sequenced_set ss3(ss); + sequenced_index &si3=get<1>(ss3); + + si3.sort(std::greater()); + si.reverse(); + BOOST_CHECK(si==si3); + } + + si2.splice(si2.end(),si,project<1>(ss,ss.find(6)),project<1>(ss,ss.find(3))); + CHECK_EQUAL(si2,{6 _ 5 _ 4}); + + si.merge(si2,std::greater()); + BOOST_CHECK(is_sorted(si,std::greater())); + BOOST_CHECK(si2.empty()); + + typedef multi_index_container< + int, + indexed_by > + > int_list; + + int_list il; + for(int i=0;i<10;++i){ + il.push_back(i); + il.push_back(i); + il.push_front(i); + il.push_front(i); + } /* 9988776655443322110000112233445566778899 */ + + il.unique(); + CHECK_EQUAL( + il, + {9 _ 8 _ 7 _ 6 _ 5 _ 4 _ 3 _ 2 _ 1 _ 0 _ + 1 _ 2 _ 3 _ 4 _ 5 _ 6 _ 7 _ 8 _ 9}); + + int_list::iterator it=il.begin(); + for(int j=0;j<9;++j,++it){} /* it points to o */ + + int_list il2; + il2.splice(il2.end(),il,il.begin(),it); + il2.reverse(); + il.merge(il2); + CHECK_EQUAL( + il, + {0 _ 1 _ 1 _ 2 _ 2 _ 3 _ 3 _ 4 _ 4 _ 5 _ 5 _ + 6 _ 6 _ 7 _ 7 _ 8 _ 8 _ 9 _ 9}); + + il.unique(same_integral_div<3>()); + CHECK_EQUAL(il,{0 _ 3 _ 6 _ 9}); + + il.unique(same_integral_div<1>()); + CHECK_EQUAL(il,{0 _ 3 _ 6 _ 9}); +} diff --git a/test/test_list_ops.hpp b/test/test_list_ops.hpp new file mode 100644 index 0000000..6c89f30 --- /dev/null +++ b/test/test_list_ops.hpp @@ -0,0 +1,11 @@ +/* Boost.MultiIndex test for standard list operations. + * + * 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. + */ + +void test_list_ops(); diff --git a/test/test_list_ops_main.cpp b/test/test_list_ops_main.cpp new file mode 100644 index 0000000..006ff72 --- /dev/null +++ b/test/test_list_ops_main.cpp @@ -0,0 +1,18 @@ +/* Boost.MultiIndex test for standard list operations. + * + * 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. + */ + +#include +#include "test_list_ops.hpp" + +int test_main(int,char *[]) +{ + test_list_ops(); + return 0; +} diff --git a/test/test_modifiers.cpp b/test/test_modifiers.cpp new file mode 100644 index 0000000..7f7eb3f --- /dev/null +++ b/test/test_modifiers.cpp @@ -0,0 +1,131 @@ +/* Boost.MultiIndex test for modifier memfuns. + * + * 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. + */ + +#include "test_modifiers.hpp" + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include "pre_multi_index.hpp" +#include "employee.hpp" +#include + +using namespace boost::multi_index; + +void test_modifiers() +{ + employee_set es; + employee_set_by_age& i2=get(es); + employee_set_as_inserted& i3=get(es); + + es.insert(employee(0,"Joe",31)); + BOOST_CHECK(es.insert(employee(0,"Joe",31)).second==false); + BOOST_CHECK(i2.insert(employee(0,"Joe Jr.",5)).second==false); + BOOST_CHECK(i3.insert(i3.begin(),employee(0,"Joe Jr.",5)).second==false); + BOOST_CHECK(i3.push_front(employee(0,"Joe Jr.",5)).second==false); + BOOST_CHECK(i3.push_back(employee(0,"Joe Jr.",5)).second==false); + + employee_set_by_age::iterator it=i2.find(31); + i2.insert(it,employee(1,"Joe Jr.",5)); + BOOST_CHECK(es.size()==2); + + employee_set_as_inserted::iterator it2=i3.begin(); + i3.insert(it2,100,employee(2,"Grandda Joe",64)); + BOOST_CHECK(es.size()==3); + + es.erase(employee(1,"Joe Jr.",5)); + BOOST_CHECK(i2.size()==2&&i3.size()==2); + + i2.erase(it); + BOOST_CHECK(es.size()==1&&i3.size()==1); + + i3.pop_front(); + BOOST_CHECK(es.size()==0&&i2.size()==0); + + es.insert(employee(0,"Joe",31)); + es.insert(employee(1,"Jack",31)); + i2.erase(31); + BOOST_CHECK(i2.size()==0); + + i3.push_front(employee(1,"Jack",31)); + i3.push_back(employee(0,"Joe",31)); + BOOST_CHECK(i3.front()==employee(1,"Jack",31)); + BOOST_CHECK(i3.back()==employee(0,"Joe",31)); + + i3.pop_back(); + BOOST_CHECK(i3.back()==employee(1,"Jack",31)); + BOOST_CHECK(es.size()==1); + + i3.pop_front(); + BOOST_CHECK(es.size()==0); + + std::vector ve; + ve.push_back(employee(3,"Anna",31)); + ve.push_back(employee(1,"Rachel",27)); + ve.push_back(employee(2,"Agatha",40)); + + i2.insert(ve.begin(),ve.end()); + BOOST_CHECK(i3.size()==3); + + i3.erase(i3.begin(),i3.end()); + BOOST_CHECK(es.size()==0); + + i3.insert(i3.end(),ve.begin(),ve.end()); + BOOST_CHECK(es.size()==3); + + es.erase(es.begin(),es.end()); + BOOST_CHECK(i2.size()==0); + + es.insert(employee(0,"Joe",31)); + es.insert(employee(1,"Robert",27)); + es.insert(employee(2,"John",40)); + es.insert(employee(3,"Albert",20)); + es.insert(employee(4,"John",57)); + + employee_set es_backup(es); + + employee_set es2; + es2.insert(employee(3,"Anna",31)); + es2.insert(employee(1,"Rachel",27)); + es2.insert(employee(2,"Agatha",40)); + + employee_set es2_backup(es2); + + i2.swap(get<2>(es2)); + BOOST_CHECK(es==es2_backup&&es2==es_backup); + + i3.swap(get<3>(es2)); + BOOST_CHECK(es==es_backup&&es2==es2_backup); + +#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)||\ + defined(BOOST_INTEL_CXX_VERSION) + ::boost::multi_index::detail::swap(i2,get<2>(es2)); +#else + using std::swap; + swap(i2,get<2>(es2)); +#endif + + BOOST_CHECK(es==es2_backup&&es2==es_backup); + +#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)||\ + defined(BOOST_INTEL_CXX_VERSION) + ::boost::multi_index::detail::swap(i3,get<3>(es2)); +#else + using std::swap; + swap(i3,get<3>(es2)); +#endif + + BOOST_CHECK(es==es_backup&&es2==es2_backup); + + i3.clear(); + BOOST_CHECK(i3.size()==0); + + es2.clear(); + BOOST_CHECK(es2.size()==0); +} diff --git a/test/test_modifiers.hpp b/test/test_modifiers.hpp new file mode 100644 index 0000000..eca90b6 --- /dev/null +++ b/test/test_modifiers.hpp @@ -0,0 +1,11 @@ +/* Boost.MultiIndex test for modifier memfuns. + * + * 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. + */ + +void test_modifiers(); diff --git a/test/test_modifiers_main.cpp b/test/test_modifiers_main.cpp new file mode 100644 index 0000000..70aebfd --- /dev/null +++ b/test/test_modifiers_main.cpp @@ -0,0 +1,20 @@ +/* Boost.MultiIndex test for modifier memfuns. + * + * 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. + */ + +#include +#include "test_modifiers.hpp" + +int test_main(int,char *[]) +{ + test_modifiers(); + return 0; +} + + diff --git a/test/test_mpl_ops.cpp b/test/test_mpl_ops.cpp new file mode 100644 index 0000000..c90544c --- /dev/null +++ b/test/test_mpl_ops.cpp @@ -0,0 +1,75 @@ +/* Boost.MultiIndex test for MPL operations. + * + * 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. + */ + +#include "test_mpl_ops.hpp" + +#include /* keep it first to prevent nasty warns in MSVC */ +#include "pre_multi_index.hpp" +#include +#include +#include +#include +#include +#include + +using namespace boost::multi_index; + +void test_mpl_ops() +{ + typedef multi_index_container< + int, + indexed_by< + ordered_unique >, + ordered_non_unique > + > + > indexed_t1; + + BOOST_STATIC_ASSERT((boost::is_same< + boost::mpl::at_c::type, + ordered_unique > >::value)); + BOOST_STATIC_ASSERT((boost::is_same< + boost::mpl::at_c::type, + ordered_non_unique > >::value)); + + typedef boost::mpl::push_front< + indexed_t1::index_specifier_type_list, + sequenced<> + >::type index_list_t; + + typedef multi_index_container< + int, + index_list_t + > indexed_t2; + + BOOST_STATIC_ASSERT((boost::is_same< + boost::mpl::at_c::type, + sequenced<> >::value)); + BOOST_STATIC_ASSERT((boost::is_same< + boost::mpl::at_c::type, + boost::mpl::at_c::type>::value)); + BOOST_STATIC_ASSERT((boost::is_same< + boost::mpl::at_c::type, + boost::mpl::at_c::type>::value)); + + typedef multi_index_container< + int, + boost::mpl::list< + ordered_unique >, + ordered_non_unique > + > + > indexed_t3; + + BOOST_STATIC_ASSERT((boost::is_same< + boost::mpl::at_c::type, + boost::mpl::at_c::type>::value)); + BOOST_STATIC_ASSERT((boost::is_same< + boost::mpl::at_c::type, + boost::mpl::at_c::type>::value)); +} diff --git a/test/test_mpl_ops.hpp b/test/test_mpl_ops.hpp new file mode 100644 index 0000000..625de75 --- /dev/null +++ b/test/test_mpl_ops.hpp @@ -0,0 +1,11 @@ +/* Boost.MultiIndex test for for MPL operations. + * + * 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. + */ + +void test_mpl_ops(); diff --git a/test/test_mpl_ops_main.cpp b/test/test_mpl_ops_main.cpp new file mode 100644 index 0000000..1b24631 --- /dev/null +++ b/test/test_mpl_ops_main.cpp @@ -0,0 +1,18 @@ +/* Boost.MultiIndex test for for MPL operations. + * + * 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. + */ + +#include +#include "test_mpl_ops.hpp" + +int test_main(int,char *[]) +{ + test_mpl_ops(); + return 0; +} diff --git a/test/test_projection.cpp b/test/test_projection.cpp new file mode 100644 index 0000000..fdace29 --- /dev/null +++ b/test/test_projection.cpp @@ -0,0 +1,109 @@ +/* Boost.MultiIndex test for projection capabilities. + * + * 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. + */ + +#include "test_projection.hpp" + +#include /* keep it first to prevent nasty warns in MSVC */ +#include "pre_multi_index.hpp" +#include "employee.hpp" +#include + +using namespace boost::multi_index; + +void test_projection() +{ + employee_set es; + es.insert(employee(0,"Joe",31)); + es.insert(employee(1,"Robert",27)); + es.insert(employee(2,"John",40)); + es.insert(employee(3,"Albert",20)); + es.insert(employee(4,"John",57)); + + employee_set::iterator it,itbis; + employee_set_by_name::iterator it1; + employee_set_by_age::iterator it2; + employee_set_as_inserted::iterator it3; + + BOOST_STATIC_ASSERT((boost::is_same< + employee_set::iterator, + nth_index_iterator::type >::value)); + BOOST_STATIC_ASSERT((boost::is_same< + employee_set_by_name::iterator, + nth_index_iterator::type >::value)); +#if defined(BOOST_NO_MEMBER_TEMPLATES) + BOOST_STATIC_ASSERT((boost::is_same< + employee_set_by_age::iterator, + index_iterator::type >::value)); +#else + BOOST_STATIC_ASSERT((boost::is_same< + employee_set_by_age::iterator, + employee_set::index_iterator::type >::value)); +#endif + BOOST_STATIC_ASSERT((boost::is_same< + employee_set_as_inserted::iterator, + nth_index_iterator::type >::value)); + + it= es.find(employee(1,"Robert",27)); + it1= project(es,it); + it2= project(es,it1); + it3= project(es,it2); +#if defined(BOOST_NO_MEMBER_TEMPLATES) + itbis=project<0>(es,it3); +#else + itbis=es.project<0>(it3); +#endif + + BOOST_CHECK(*it==*it1&&*it1==*it2&&*it2==*it3&&itbis==it); + + const employee_set& ces=es; + + employee_set::const_iterator cit,citbis; + employee_set_by_name::const_iterator cit1; + employee_set_by_age::const_iterator cit2; + employee_set_as_inserted::const_iterator cit3; + + BOOST_STATIC_ASSERT((boost::is_same< + employee_set::const_iterator, + nth_index_const_iterator::type >::value)); + BOOST_STATIC_ASSERT((boost::is_same< + employee_set_by_name::const_iterator, + nth_index_const_iterator::type >::value)); +#if defined(BOOST_NO_MEMBER_TEMPLATES) + BOOST_STATIC_ASSERT((boost::is_same< + employee_set_by_age::const_iterator, + index_const_iterator::type >::value)); +#else + BOOST_STATIC_ASSERT((boost::is_same< + employee_set_by_age::const_iterator, + employee_set::index_const_iterator::type >::value)); +#endif + BOOST_STATIC_ASSERT((boost::is_same< + employee_set_as_inserted::const_iterator, + nth_index_const_iterator::type >::value)); + + BOOST_CHECK(project(es,es.end())==get(es).end()); + BOOST_CHECK(project(es,es.end())==get(es).end()); + + cit= ces.find(employee(4,"John",57)); +#if defined(BOOST_NO_MEMBER_TEMPLATES) + cit1= project(ces,cit); +#else + cit1= ces.project(cit); +#endif + cit2= project(ces,cit1); +#if defined(BOOST_NO_MEMBER_TEMPLATES) + cit3= project(ces,cit2); +#else + cit3= ces.project(cit2); +#endif + citbis=project<0>(ces,cit3); + + BOOST_CHECK(*cit==*cit1&&*cit1==*cit2&&*cit2==*cit3&&citbis==cit); +} diff --git a/test/test_projection.hpp b/test/test_projection.hpp new file mode 100644 index 0000000..fb381af --- /dev/null +++ b/test/test_projection.hpp @@ -0,0 +1,11 @@ +/* Boost.MultiIndex test for projection capabilities. + * + * 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. + */ + +void test_projection(); diff --git a/test/test_projection_main.cpp b/test/test_projection_main.cpp new file mode 100644 index 0000000..be06652 --- /dev/null +++ b/test/test_projection_main.cpp @@ -0,0 +1,20 @@ +/* Boost.MultiIndex test for projection capabilities. + * + * 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. + */ + +#include +#include "test_projection.hpp" + +int test_main(int,char *[]) +{ + test_projection(); + return 0; +} + + diff --git a/test/test_range.cpp b/test/test_range.cpp new file mode 100644 index 0000000..74d8e27 --- /dev/null +++ b/test/test_range.cpp @@ -0,0 +1,118 @@ +/* Boost.MultiIndex test for range(). + * + * 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. + */ + +#include "test_range.hpp" + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include +#include "pre_multi_index.hpp" +#include +#include +#include +#include + +using namespace boost::multi_index; + +typedef multi_index_container int_set; +typedef int_set::iterator int_set_iterator; + +#undef _ +#define _ , + +#undef CHECK_RANGE +#define CHECK_RANGE(p,check_range) \ +{\ + int v[]=check_range;\ + std::size_t size_v=sizeof(v)/sizeof(int);\ + BOOST_CHECK(std::size_t(std::distance((p).first,(p).second))==size_v);\ + BOOST_CHECK(std::equal((p).first,(p).second,v));\ +} + +#undef CHECK_VOID_RANGE +#define CHECK_VOID_RANGE(p) BOOST_CHECK((p).first==(p).second) + +void test_range() +{ + int_set is; + + for(int i=1;i<=10;++i)is.insert(i); + + std::pair p; + + p=is.range(unbounded,unbounded); + CHECK_RANGE(p,{1 _ 2 _ 3 _ 4 _ 5 _ 6 _ 7 _ 8 _ 9 _ 10}); + + p=is.range( + std::bind1st(std::less(),5), /* 5 < x */ + unbounded); + CHECK_RANGE(p,{6 _ 7 _ 8 _ 9 _ 10}); + + p=is.range( + std::bind1st(std::less_equal(),8), /* 8 <= x */ + unbounded); + CHECK_RANGE(p,{8 _ 9 _ 10}); + + p=is.range( + std::bind1st(std::less_equal(),11), /* 11 <= x */ + unbounded); + CHECK_VOID_RANGE(p); + + p=is.range( + unbounded, + std::bind2nd(std::less(),8)); /* x < 8 */ + CHECK_RANGE(p,{1 _ 2 _ 3 _ 4 _ 5 _ 6 _ 7}); + + p=is.range( + unbounded, + std::bind2nd(std::less_equal(),4)); /* x <= 4 */ + CHECK_RANGE(p,{1 _ 2 _ 3 _ 4}); + + p=is.range( + unbounded, + std::bind2nd(std::less_equal(),0)); /* x <= 0 */ + CHECK_VOID_RANGE(p); + + p=is.range( + std::bind1st(std::less(),6), /* 6 < x */ + std::bind2nd(std::less_equal(),9)); /* x <= 9 */ + CHECK_RANGE(p,{7 _ 8 _ 9}); + + p=is.range( + std::bind1st(std::less_equal(),4), /* 4 <= x */ + std::bind2nd(std::less(),5)); /* x < 5 */ + CHECK_RANGE(p,{4}); + + p=is.range( + std::bind1st(std::less_equal(),10), /* 10 <= x */ + std::bind2nd(std::less_equal(),10)); /* x <= 10 */ + CHECK_RANGE(p,{10}); + + p=is.range( + std::bind1st(std::less(),0), /* 0 < x */ + std::bind2nd(std::less(),11)); /* x < 11 */ + CHECK_RANGE(p,{1 _ 2 _ 3 _ 4 _ 5 _ 6 _ 7 _ 8 _ 9 _ 10}); + + p=is.range( + std::bind1st(std::less(),7), /* 7 < x */ + std::bind2nd(std::less_equal(),7)); /* x <= 7 */ + CHECK_VOID_RANGE(p); + + p=is.range( + std::bind1st(std::less_equal(),8), /* 8 <= x */ + std::bind2nd(std::less(),2)); /* x < 2 */ + CHECK_VOID_RANGE(p); + + p=is.range( + std::bind1st(std::less(),4), /* 4 < x */ + std::bind2nd(std::less(),5)); /* x < 5 */ + CHECK_VOID_RANGE(p); + BOOST_CHECK(p.first!=is.end()&&p.second!=is.end()); +} diff --git a/test/test_range.hpp b/test/test_range.hpp new file mode 100644 index 0000000..396ac79 --- /dev/null +++ b/test/test_range.hpp @@ -0,0 +1,11 @@ +/* Boost.MultiIndex test for range(). + * + * 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. + */ + +void test_range(); diff --git a/test/test_range_main.cpp b/test/test_range_main.cpp new file mode 100644 index 0000000..530abd1 --- /dev/null +++ b/test/test_range_main.cpp @@ -0,0 +1,18 @@ +/* Boost.MultiIndex test for range(). + * + * 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. + */ + +#include +#include "test_range.hpp" + +int test_main(int,char *[]) +{ + test_range(); + return 0; +} diff --git a/test/test_safe_mode.cpp b/test/test_safe_mode.cpp new file mode 100644 index 0000000..8d9f783 --- /dev/null +++ b/test/test_safe_mode.cpp @@ -0,0 +1,195 @@ +/* Boost.MultiIndex test for safe_mode. + * + * 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. + */ + +#include "test_safe_mode.hpp" + +#include /* keep it first to prevent nasty warns in MSVC */ +#include "pre_multi_index.hpp" +#include "employee.hpp" +#include "pair_of_ints.hpp" +#include +#include + +using namespace boost::multi_index; + +#define TRY_SAFE_MODE \ +try{ + +#define CATCH_SAFE_MODE(err) \ + throw std::runtime_error("safe mode violation not detected");\ +}catch(const safe_mode_exception& e){\ + if(e.error_code!=(err))throw std::runtime_error(\ + "safe mode violation not expected");\ +} + +struct change_id +{ + change_id(int new_id_):new_id(new_id_){} + void operator()(employee& e){e.id=new_id;} + +private: + int new_id; +}; + +typedef multi_index_container< + pair_of_ints, + indexed_by< + ordered_unique, + ordered_unique > > +int_int_set; + +void test_safe_mode() +{ + employee_set es,es2; + employee_set_as_inserted& i=get(es); + es.insert(employee(0,"Joe",31)); + + TRY_SAFE_MODE + employee_set::iterator it; + employee e=*it; + CATCH_SAFE_MODE(safe_mode::invalid_iterator) + + TRY_SAFE_MODE + employee_set::iterator it=es.end(); + employee e=*it; + CATCH_SAFE_MODE(safe_mode::not_dereferenceable_iterator) + + TRY_SAFE_MODE + employee_set::iterator it=es.end(); + ++it; + CATCH_SAFE_MODE(safe_mode::not_incrementable_iterator) + + TRY_SAFE_MODE + employee_set::iterator it=es.begin(); + --it; + CATCH_SAFE_MODE(safe_mode::not_decrementable_iterator) + + TRY_SAFE_MODE + employee_set::iterator it; + employee_set::iterator it2; + bool b=(it==it2); + b=true; /* avoid warning about unused var */ + CATCH_SAFE_MODE(safe_mode::invalid_iterator) + + TRY_SAFE_MODE + employee_set::iterator it=es.begin(); + employee_set::iterator it2; + bool b=(it==it2); + b=true; /* avoid warning about unused var */ + CATCH_SAFE_MODE(safe_mode::invalid_iterator) + + TRY_SAFE_MODE + employee_set::iterator it=es.begin(); + employee_set::iterator it2=es2.begin(); + bool b=(it==it2); + b=true; /* avoid warning about unused var */ + CATCH_SAFE_MODE(safe_mode::not_same_owner) + + TRY_SAFE_MODE + es.erase(es.end(),es.begin()); + CATCH_SAFE_MODE(safe_mode::invalid_range) + + TRY_SAFE_MODE + employee_set::iterator it; + es.insert(it,employee(0,"Joe",31)); + CATCH_SAFE_MODE(safe_mode::invalid_iterator) + + TRY_SAFE_MODE + es.erase(es.end()); + CATCH_SAFE_MODE(safe_mode::not_dereferenceable_iterator) + + TRY_SAFE_MODE + employee_set::iterator it=es.begin(); + es2.insert(it,employee(0,"Joe",31)); + CATCH_SAFE_MODE(safe_mode::not_owner) + + TRY_SAFE_MODE + employee_set::iterator it=es.begin(); + employee_set::iterator it2=es2.end(); + es2.erase(it,it2); + CATCH_SAFE_MODE(safe_mode::not_owner) + + TRY_SAFE_MODE + employee_set::iterator it=es.insert(employee(1,"Robert",27)).first; + es.erase(it); + es.erase(it); + CATCH_SAFE_MODE(safe_mode::invalid_iterator) + + TRY_SAFE_MODE + employee_set::iterator it; + { + employee_set es3; + it=es3.insert(employee(0,"Joe",31)).first; + } + employee e=*it; + CATCH_SAFE_MODE(safe_mode::invalid_iterator) + + TRY_SAFE_MODE + employee_set es3(es); + employee_set es4; + employee_set::iterator it=es3.begin(); + es3.swap(es4); + es3.erase(it); + CATCH_SAFE_MODE(safe_mode::not_owner) + + /* this, unlike the previous case, is indeed correct, test safe mode + * gets it right + */ + { + employee_set es3(es); + employee_set es4; + employee_set::iterator it=es3.begin(); + es3.swap(es4); + es4.erase(it); + } + + TRY_SAFE_MODE + employee_set::iterator it=es.insert(employee(1,"Robert",27)).first; + employee_set_by_name::iterator it2=project(es,it); + es.modify_key(it,change_id(0)); + employee e=*it2; + CATCH_SAFE_MODE(safe_mode::invalid_iterator) + + TRY_SAFE_MODE + int_int_set iis; + int_int_set::iterator it=iis.insert(pair_of_ints(0,0)).first; + iis.insert(pair_of_ints(1,1)); + iis.modify(it,increment_first); + pair_of_ints p=*it; + p.first=0; /* avoid warning about unused var */ + CATCH_SAFE_MODE(safe_mode::invalid_iterator) + + TRY_SAFE_MODE + int_int_set iis; + int_int_set::iterator it=iis.insert(pair_of_ints(0,0)).first; + iis.insert(pair_of_ints(1,1)); + iis.modify(it,increment_second); + pair_of_ints p=*it; + p.first=0; /* avoid warning about unused var */ + CATCH_SAFE_MODE(safe_mode::invalid_iterator) + + TRY_SAFE_MODE + employee_set::iterator it=es.end(); + employee_set_by_name::iterator it2=project(es2,it); + CATCH_SAFE_MODE(safe_mode::not_owner) + + TRY_SAFE_MODE + employee_set_by_name::iterator it=get(es).end(); + employee_set::iterator it2=project<0>(es2,it); + CATCH_SAFE_MODE(safe_mode::not_owner) + + TRY_SAFE_MODE + i.splice(i.begin(),i,i.begin(),i.end()); + CATCH_SAFE_MODE(safe_mode::inside_range) + + TRY_SAFE_MODE + i.splice(i.begin(),i); + CATCH_SAFE_MODE(safe_mode::same_container) +} diff --git a/test/test_safe_mode.hpp b/test/test_safe_mode.hpp new file mode 100644 index 0000000..4597b1e --- /dev/null +++ b/test/test_safe_mode.hpp @@ -0,0 +1,11 @@ +/* Boost.MultiIndex test for safe mode. + * + * 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. + */ + +void test_safe_mode(); diff --git a/test/test_safe_mode_main.cpp b/test/test_safe_mode_main.cpp new file mode 100644 index 0000000..382f2f8 --- /dev/null +++ b/test/test_safe_mode_main.cpp @@ -0,0 +1,19 @@ +/* Boost.MultiIndex test for safe mode. + * + * 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. + */ + +#include +#include "test_safe_mode.hpp" + +int test_main(int,char *[]) +{ + test_safe_mode(); + return 0; +} + diff --git a/test/test_set_ops.cpp b/test/test_set_ops.cpp new file mode 100644 index 0000000..38a7d1d --- /dev/null +++ b/test/test_set_ops.cpp @@ -0,0 +1,50 @@ +/* Boost.MultiIndex test for standard set operations. + * + * 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. + */ + +#include "test_set_ops.hpp" + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include +#include "pre_multi_index.hpp" +#include "employee.hpp" +#include + +using namespace boost::multi_index; + +void test_set_ops() +{ + employee_set es; + employee_set_by_name& i1=get(es); + const employee_set_by_age& i2=get(es); + + es.insert(employee(0,"Joe",31)); + es.insert(employee(1,"Robert",27)); + es.insert(employee(2,"John",40)); + es.insert(employee(3,"Albert",20)); + es.insert(employee(4,"John",57)); + + BOOST_CHECK(i1.find("John")->name=="John"); + BOOST_CHECK(i2.find(41)==i2.end()); + + BOOST_CHECK(i1.count("John")==2); + BOOST_CHECK(es.count(employee(10,"",-1))==0); + + BOOST_CHECK(i1.lower_bound("John")->name=="John"); + + BOOST_CHECK( + std::distance( + i2.lower_bound(31), + i2.upper_bound(60))==3); + + std::pair p= + i1.equal_range("John"); + BOOST_CHECK(std::distance(p.first,p.second)==2); +} diff --git a/test/test_set_ops.hpp b/test/test_set_ops.hpp new file mode 100644 index 0000000..98128a6 --- /dev/null +++ b/test/test_set_ops.hpp @@ -0,0 +1,11 @@ +/* Boost.MultiIndex test for standard set operations. + * + * 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. + */ + +void test_set_ops(); diff --git a/test/test_set_ops_main.cpp b/test/test_set_ops_main.cpp new file mode 100644 index 0000000..f233c24 --- /dev/null +++ b/test/test_set_ops_main.cpp @@ -0,0 +1,18 @@ +/* Boost.MultiIndex test for standard set operations. + * + * 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. + */ + +#include +#include "test_set_ops.hpp" + +int test_main(int,char *[]) +{ + test_set_ops(); + return 0; +} diff --git a/test/test_special_list_ops.cpp b/test/test_special_list_ops.cpp new file mode 100644 index 0000000..61a9a06 --- /dev/null +++ b/test/test_special_list_ops.cpp @@ -0,0 +1,83 @@ +/* Boost.MultiIndex test for special list operations. + * + * 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. + */ + +#include "test_special_list_ops.hpp" + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include +#include "pre_multi_index.hpp" +#include +#include +#include + +using namespace boost::multi_index; + +#undef _ +#define _ , + +#undef CHECK_EQUAL +#define CHECK_EQUAL(p,check_range) \ +{\ + int v[]=check_range;\ + std::size_t size_v=sizeof(v)/sizeof(int);\ + BOOST_CHECK(std::size_t(std::distance((p).begin(),(p).end()))==size_v);\ + BOOST_CHECK(std::equal((p).begin(),(p).end(),v));\ +} + +#undef CHECK_VOID_RANGE +#define CHECK_VOID_RANGE(p) BOOST_CHECK((p).first==(p).second) + +void test_special_list_ops() +{ + typedef multi_index_container< + int, + indexed_by< + sequenced<> + > + > sequenced_container; + + sequenced_container sc; + sc.push_back(0); + sc.push_back(1); + sc.push_back(2); + sc.push_back(3); + sc.push_back(4); + sc.push_back(5); + + sequenced_container::iterator it; + + it=sc.begin(); + std::advance(it,3); + sc.relocate(sc.begin(),it); + CHECK_EQUAL(sc,{3 _ 0 _ 1 _ 2 _ 4 _ 5}); + BOOST_CHECK(it==sc.begin()); + + sc.relocate(it,it); + CHECK_EQUAL(sc,{3 _ 0 _ 1 _ 2 _ 4 _ 5}); + + std::advance(it,3); + sc.relocate(sc.end(),it,sc.end()); + CHECK_EQUAL(sc,{3 _ 0 _ 1 _ 2 _ 4 _ 5}); + + sc.relocate(sc.begin(),it,it); + CHECK_EQUAL(sc,{3 _ 0 _ 1 _ 2 _ 4 _ 5}); + + sequenced_container::iterator it2; + + it2=sc.begin(); + ++it2; + sc.relocate(it2,it,sc.end()); + CHECK_EQUAL(sc,{3 _ 2 _ 4 _ 5 _ 0 _ 1}); + BOOST_CHECK(std::distance(it,it2)==3); + + sc.relocate(--(sc.end()),it,it2); + CHECK_EQUAL(sc,{3 _ 0 _ 2 _ 4 _ 5 _ 1}); +} diff --git a/test/test_special_list_ops.hpp b/test/test_special_list_ops.hpp new file mode 100644 index 0000000..fc95f54 --- /dev/null +++ b/test/test_special_list_ops.hpp @@ -0,0 +1,11 @@ +/* Boost.MultiIndex test for special list operations. + * + * 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. + */ + +void test_special_list_ops(); diff --git a/test/test_special_list_ops_main.cpp b/test/test_special_list_ops_main.cpp new file mode 100644 index 0000000..bee82a9 --- /dev/null +++ b/test/test_special_list_ops_main.cpp @@ -0,0 +1,18 @@ +/* Boost.MultiIndex test for special list operations. + * + * 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. + */ + +#include +#include "test_special_list_ops.hpp" + +int test_main(int,char *[]) +{ + test_special_list_ops(); + return 0; +} diff --git a/test/test_special_set_ops.cpp b/test/test_special_set_ops.cpp new file mode 100644 index 0000000..350b73c --- /dev/null +++ b/test/test_special_set_ops.cpp @@ -0,0 +1,59 @@ +/* Boost.MultiIndex test for special set operations. + * + * 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. + */ + +#include "test_special_set_ops.hpp" + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include "pre_multi_index.hpp" +#include "employee.hpp" +#include + +using namespace boost::multi_index; + +struct comp_initial +{ + bool operator()(char ch,const std::string& s)const + { + if(s.empty())return false; + return ch(es).lower_bound('J',comp_initial()), + get(es).upper_bound('J',comp_initial()))==3); + + BOOST_CHECK(get(es).find('A',comp_initial())->name[0]=='A'); + + BOOST_CHECK( + std::distance( + get(es).lower_bound(27), + get(es).upper_bound(40))==3); + + BOOST_CHECK(es.count(2,employee::comp_id())==1); + BOOST_CHECK(es.count(5,employee::comp_id())==0); +} diff --git a/test/test_special_set_ops.hpp b/test/test_special_set_ops.hpp new file mode 100644 index 0000000..78d4ce2 --- /dev/null +++ b/test/test_special_set_ops.hpp @@ -0,0 +1,11 @@ +/* Boost.MultiIndex test for special set operations. + * + * 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. + */ + +void test_special_set_ops(); diff --git a/test/test_special_set_ops_main.cpp b/test/test_special_set_ops_main.cpp new file mode 100644 index 0000000..4530df6 --- /dev/null +++ b/test/test_special_set_ops_main.cpp @@ -0,0 +1,18 @@ +/* Boost.MultiIndex test for special set operations. + * + * 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. + */ + +#include +#include "test_special_set_ops.hpp" + +int test_main(int,char *[]) +{ + test_special_set_ops(); + return 0; +} diff --git a/test/test_update.cpp b/test/test_update.cpp new file mode 100644 index 0000000..b17b9ef --- /dev/null +++ b/test/test_update.cpp @@ -0,0 +1,86 @@ +/* Boost.MultiIndex test for replace(), modify() and modify_key(). + * + * 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. + */ + +#include "test_update.hpp" + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include "pre_multi_index.hpp" +#include "employee.hpp" +#include "pair_of_ints.hpp" +#include + +using namespace boost::multi_index; + +void test_update() +{ + employee_set es; + employee_set_as_inserted& i=get(es); + + es.insert(employee(0,"Joe",31)); + es.insert(employee(1,"Robert",27)); + es.insert(employee(2,"John",40)); + es.insert(employee(3,"Olbert",20)); + es.insert(employee(4,"John",57)); + + employee_set::iterator it=es.find(employee(0,"Joe",31)); + employee_set_as_inserted::iterator it1= + project(es,get(es).find("Olbert")); + + BOOST_CHECK(es.replace(it,*it)); + BOOST_CHECK(!es.replace(it,employee(3,"Joe",31))&&it->id==0); + BOOST_CHECK(es.replace(it,employee(0,"Joe",32))&&it->age==32); + BOOST_CHECK(i.replace(it1,employee(3,"Albert",20))&&it1->name=="Albert"); + + typedef multi_index_container< + pair_of_ints, + indexed_by< + ordered_unique, + ordered_unique, + sequenced<> > > + int_int_set; + + int_int_set iis; + nth_index::type& iii=get<2>(iis); + iis.insert(pair_of_ints(0,0)); + iis.insert(pair_of_ints(5,5)); + iis.insert(pair_of_ints(10,10)); + + BOOST_CHECK(!iis.replace(iis.begin(),pair_of_ints(5,0))); + BOOST_CHECK(!iii.replace(iii.begin(),pair_of_ints(0,5))); + BOOST_CHECK(!iis.replace(iis.begin(),pair_of_ints(5,11))); + BOOST_CHECK(!iis.replace(iis.begin(),pair_of_ints(11,5))); + + BOOST_CHECK(iis.modify(iis.begin(),increment_first)); + BOOST_CHECK(iii.modify(iii.begin(),increment_first)); + BOOST_CHECK(iis.modify(iis.begin(),increment_first)); + BOOST_CHECK(iii.modify(iii.begin(),increment_first)); + + BOOST_CHECK(!iis.modify(iis.begin(),increment_first)); + BOOST_CHECK(iis.size()==2); + + iis.insert(pair_of_ints(0,0)); + BOOST_CHECK(iii.modify(--iii.end(),increment_second)); + BOOST_CHECK(iis.modify(iis.begin(),increment_second)); + BOOST_CHECK(iii.modify(--iii.end(),increment_second)); + BOOST_CHECK(iis.modify(iis.begin(),increment_second)); + + BOOST_CHECK(!iii.modify(--iii.end(),increment_second)); + BOOST_CHECK(iii.size()==2); + + iis.insert(pair_of_ints(0,0)); + BOOST_CHECK(iis.modify_key(iis.begin(),increment_int)); + BOOST_CHECK(iis.modify_key(iis.begin(),increment_int)); + BOOST_CHECK(iis.modify_key(iis.begin(),increment_int)); + BOOST_CHECK(iis.modify_key(iis.begin(),increment_int)); + + BOOST_CHECK(!iis.modify_key(iis.begin(),increment_int)); + BOOST_CHECK(iis.size()==2); +} diff --git a/test/test_update.hpp b/test/test_update.hpp new file mode 100644 index 0000000..c6fad09 --- /dev/null +++ b/test/test_update.hpp @@ -0,0 +1,11 @@ +/* Boost.MultiIndex test for replace(), modify() and modify_key(). + * + * 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. + */ + +void test_update(); diff --git a/test/test_update_main.cpp b/test/test_update_main.cpp new file mode 100644 index 0000000..ebc850a --- /dev/null +++ b/test/test_update_main.cpp @@ -0,0 +1,18 @@ +/* Boost.MultiIndex test for replace(), modify() and modify_key(). + * + * 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. + */ + +#include +#include "test_update.hpp" + +int test_main(int,char *[]) +{ + test_update(); + return 0; +}