stabilize build system: depends, installer, boost/bdb fixes, cross targets groundwork

This commit is contained in:
2026-02-24 18:38:47 +00:00
parent da8c28aaeb
commit 65cb2619a7
13106 changed files with 2484322 additions and 1804 deletions
@@ -0,0 +1,54 @@
/* Copyright 2003-2013 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_ACCESS_SPECIFIER_HPP
#define BOOST_MULTI_INDEX_DETAIL_ACCESS_SPECIFIER_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp>
#include <boost/detail/workaround.hpp>
/* 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 public
#define BOOST_MULTI_INDEX_PRIVATE_IF_MEMBER_TEMPLATE_FRIENDS public
#else
#define BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS protected
#define BOOST_MULTI_INDEX_PRIVATE_IF_MEMBER_TEMPLATE_FRIENDS private
#endif
/* GCC does not correctly support in-class using declarations for template
* functions. See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=9810
* MSVC 7.1/8.0 seem to have a similar problem, though the conditions in
* which the error happens are not that simple. I have yet to isolate this
* into a snippet suitable for bug reporting.
* Sun Studio also has this problem, which might be related, from the
* information gathered at Sun forums, with a known issue notified at the
* internal bug report 6421933. The bug is present up to Studio Express 2,
* the latest preview version of the future Sun Studio 12. As of this writing
* (October 2006) it is not known whether a fix will finally make it into the
* official Sun Studio 12.
*/
#if BOOST_WORKAROUND(__GNUC__,==3)&&(__GNUC_MINOR__<4)||\
BOOST_WORKAROUND(BOOST_MSVC,==1310)||\
BOOST_WORKAROUND(BOOST_MSVC,==1400)||\
BOOST_WORKAROUND(__SUNPRO_CC,BOOST_TESTED_AT(0x590))
#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
@@ -0,0 +1,44 @@
/* Copyright 2003-2013 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_ADL_SWAP_HPP
#define BOOST_MULTI_INDEX_DETAIL_ADL_SWAP_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <algorithm>
namespace boost{
namespace multi_index{
namespace detail{
template<typename T>
void adl_swap(T& x,T& y)
{
#if !defined(BOOST_FUNCTION_SCOPE_USING_DECLARATION_BREAKS_ADL)
using std::swap;
swap(x,y);
#else
std::swap(x,y);
#endif
}
} /* namespace multi_index::detail */
} /* namespace multi_index */
} /* namespace boost */
#endif
@@ -0,0 +1,83 @@
/* Copyright 2003-2016 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_ARCHIVE_CONSTRUCTED_HPP
#define BOOST_MULTI_INDEX_DETAIL_ARCHIVE_CONSTRUCTED_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <boost/detail/no_exceptions_support.hpp>
#include <boost/noncopyable.hpp>
#include <boost/serialization/serialization.hpp>
#include <boost/type_traits/aligned_storage.hpp>
#include <boost/type_traits/alignment_of.hpp>
namespace boost{
namespace multi_index{
namespace detail{
/* constructs a stack-based object from a serialization archive */
template<typename T>
struct archive_constructed:private noncopyable
{
template<class Archive>
archive_constructed(Archive& ar,const unsigned int version)
{
serialization::load_construct_data_adl(ar,&get(),version);
BOOST_TRY{
ar>>get();
}
BOOST_CATCH(...){
(&get())->~T();
BOOST_RETHROW;
}
BOOST_CATCH_END
}
template<class Archive>
archive_constructed(const char* name,Archive& ar,const unsigned int version)
{
serialization::load_construct_data_adl(ar,&get(),version);
BOOST_TRY{
ar>>serialization::make_nvp(name,get());
}
BOOST_CATCH(...){
(&get())->~T();
BOOST_RETHROW;
}
BOOST_CATCH_END
}
~archive_constructed()
{
(&get())->~T();
}
#include <boost/multi_index/detail/ignore_wstrict_aliasing.hpp>
T& get(){return *reinterpret_cast<T*>(&space);}
#include <boost/multi_index/detail/restore_wstrict_aliasing.hpp>
private:
typename aligned_storage<sizeof(T),alignment_of<T>::value>::type space;
};
} /* namespace multi_index::detail */
} /* namespace multi_index */
} /* namespace boost */
#endif
@@ -0,0 +1,91 @@
/* Copyright 2003-2013 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_AUTO_SPACE_HPP
#define BOOST_MULTI_INDEX_DETAIL_AUTO_SPACE_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <algorithm>
#include <boost/detail/allocator_utilities.hpp>
#include <boost/multi_index/detail/adl_swap.hpp>
#include <boost/noncopyable.hpp>
#include <memory>
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://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#199
*/
template<typename T,typename Allocator=std::allocator<T> >
struct auto_space:private noncopyable
{
typedef typename boost::detail::allocator::rebind_to<
Allocator,T
>::type::pointer pointer;
explicit auto_space(const Allocator& al=Allocator(),std::size_t n=1):
al_(al),n_(n),data_(n_?al_.allocate(n_):pointer(0))
{}
~auto_space()
{
if(n_)al_.deallocate(data_,n_);
}
Allocator get_allocator()const{return al_;}
pointer data()const{return data_;}
void swap(auto_space& x)
{
if(al_!=x.al_)adl_swap(al_,x.al_);
std::swap(n_,x.n_);
std::swap(data_,x.data_);
}
private:
typename boost::detail::allocator::rebind_to<
Allocator,T>::type al_;
std::size_t n_;
pointer data_;
};
template<typename T,typename Allocator>
void swap(auto_space<T,Allocator>& x,auto_space<T,Allocator>& y)
{
x.swap(y);
}
} /* namespace multi_index::detail */
} /* namespace multi_index */
} /* namespace boost */
#endif
@@ -0,0 +1,74 @@
/* Copyright 2003-2013 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_BASE_TYPE_HPP
#define BOOST_MULTI_INDEX_DETAIL_BASE_TYPE_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <boost/detail/workaround.hpp>
#include <boost/mpl/at.hpp>
#include <boost/mpl/apply.hpp>
#include <boost/mpl/size.hpp>
#include <boost/multi_index/detail/index_base.hpp>
#include <boost/multi_index/detail/is_index_list.hpp>
#include <boost/static_assert.hpp>
namespace boost{
namespace multi_index{
namespace detail{
/* MPL machinery to construct a linear hierarchy of indices out of
* a index list.
*/
struct index_applier
{
template<typename IndexSpecifierMeta,typename SuperMeta>
struct apply
{
typedef typename IndexSpecifierMeta::type index_specifier;
typedef typename index_specifier::
BOOST_NESTED_TEMPLATE index_class<SuperMeta>::type type;
};
};
template<int N,typename Value,typename IndexSpecifierList,typename Allocator>
struct nth_layer
{
BOOST_STATIC_CONSTANT(int,length=mpl::size<IndexSpecifierList>::value);
typedef typename mpl::eval_if_c<
N==length,
mpl::identity<index_base<Value,IndexSpecifierList,Allocator> >,
mpl::apply2<
index_applier,
mpl::at_c<IndexSpecifierList,N>,
nth_layer<N+1,Value,IndexSpecifierList,Allocator>
>
>::type type;
};
template<typename Value,typename IndexSpecifierList,typename Allocator>
struct multi_index_base_type:nth_layer<0,Value,IndexSpecifierList,Allocator>
{
BOOST_STATIC_ASSERT(detail::is_index_list<IndexSpecifierList>::value);
};
} /* namespace multi_index::detail */
} /* namespace multi_index */
} /* namespace boost */
#endif
@@ -0,0 +1,114 @@
/* Copyright 2003-2014 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_BIDIR_NODE_ITERATOR_HPP
#define BOOST_MULTI_INDEX_DETAIL_BIDIR_NODE_ITERATOR_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <boost/operators.hpp>
#if !defined(BOOST_MULTI_INDEX_DISABLE_SERIALIZATION)
#include <boost/serialization/nvp.hpp>
#include <boost/serialization/split_member.hpp>
#endif
namespace boost{
namespace multi_index{
namespace detail{
/* Iterator class for node-based indices with bidirectional
* iterators (ordered and sequenced indices.)
*/
template<typename Node>
class bidir_node_iterator:
public bidirectional_iterator_helper<
bidir_node_iterator<Node>,
typename Node::value_type,
std::ptrdiff_t,
const typename Node::value_type*,
const typename Node::value_type&>
{
public:
/* coverity[uninit_ctor]: suppress warning */
bidir_node_iterator(){}
explicit bidir_node_iterator(Node* node_):node(node_){}
const typename Node::value_type& operator*()const
{
return node->value();
}
bidir_node_iterator& operator++()
{
Node::increment(node);
return *this;
}
bidir_node_iterator& operator--()
{
Node::decrement(node);
return *this;
}
#if !defined(BOOST_MULTI_INDEX_DISABLE_SERIALIZATION)
/* Serialization. As for why the following is public,
* see explanation in safe_mode_iterator notes in safe_mode.hpp.
*/
BOOST_SERIALIZATION_SPLIT_MEMBER()
typedef typename Node::base_type node_base_type;
template<class Archive>
void save(Archive& ar,const unsigned int)const
{
node_base_type* bnode=node;
ar<<serialization::make_nvp("pointer",bnode);
}
template<class Archive>
void load(Archive& ar,const unsigned int)
{
node_base_type* bnode;
ar>>serialization::make_nvp("pointer",bnode);
node=static_cast<Node*>(bnode);
}
#endif
/* get_node is not to be used by the user */
typedef Node node_type;
Node* get_node()const{return node;}
private:
Node* node;
};
template<typename Node>
bool operator==(
const bidir_node_iterator<Node>& x,
const bidir_node_iterator<Node>& y)
{
return x.get_node()==y.get_node();
}
} /* namespace multi_index::detail */
} /* namespace multi_index */
} /* namespace boost */
#endif
@@ -0,0 +1,243 @@
/* Copyright 2003-2015 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_BUCKET_ARRAY_HPP
#define BOOST_MULTI_INDEX_DETAIL_BUCKET_ARRAY_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <algorithm>
#include <boost/multi_index/detail/auto_space.hpp>
#include <boost/multi_index/detail/hash_index_node.hpp>
#include <boost/noncopyable.hpp>
#include <boost/preprocessor/repetition/repeat.hpp>
#include <boost/preprocessor/seq/elem.hpp>
#include <boost/preprocessor/seq/enum.hpp>
#include <boost/preprocessor/seq/size.hpp>
#include <cstddef>
#include <limits.h>
#if !defined(BOOST_MULTI_INDEX_DISABLE_SERIALIZATION)
#include <boost/archive/archive_exception.hpp>
#include <boost/serialization/access.hpp>
#include <boost/throw_exception.hpp>
#endif
namespace boost{
namespace multi_index{
namespace detail{
/* bucket structure for use by hashed indices */
#define BOOST_MULTI_INDEX_BA_SIZES_32BIT \
(53ul)(97ul)(193ul)(389ul)(769ul) \
(1543ul)(3079ul)(6151ul)(12289ul)(24593ul) \
(49157ul)(98317ul)(196613ul)(393241ul)(786433ul) \
(1572869ul)(3145739ul)(6291469ul)(12582917ul)(25165843ul) \
(50331653ul)(100663319ul)(201326611ul)(402653189ul)(805306457ul) \
(1610612741ul)(3221225473ul)
#if ((((ULONG_MAX>>16)>>16)>>16)>>15)==0 /* unsigned long less than 64 bits */
#define BOOST_MULTI_INDEX_BA_SIZES \
BOOST_MULTI_INDEX_BA_SIZES_32BIT \
(4294967291ul)
#else
/* obtained with aid from
* http://javaboutique.internet.com/prime_numb/
* http://www.rsok.com/~jrm/next_ten_primes.html
* and verified with
* http://www.alpertron.com.ar/ECM.HTM
*/
#define BOOST_MULTI_INDEX_BA_SIZES \
BOOST_MULTI_INDEX_BA_SIZES_32BIT \
(6442450939ul)(12884901893ul)(25769803751ul)(51539607551ul) \
(103079215111ul)(206158430209ul)(412316860441ul)(824633720831ul) \
(1649267441651ul)(3298534883309ul)(6597069766657ul)(13194139533299ul) \
(26388279066623ul)(52776558133303ul)(105553116266489ul)(211106232532969ul) \
(422212465066001ul)(844424930131963ul)(1688849860263953ul) \
(3377699720527861ul)(6755399441055731ul)(13510798882111483ul) \
(27021597764222939ul)(54043195528445957ul)(108086391056891903ul) \
(216172782113783843ul)(432345564227567621ul)(864691128455135207ul) \
(1729382256910270481ul)(3458764513820540933ul)(6917529027641081903ul) \
(13835058055282163729ul)(18446744073709551557ul)
#endif
template<bool _=true> /* templatized to have in-header static var defs */
class bucket_array_base:private noncopyable
{
protected:
static const std::size_t sizes[
BOOST_PP_SEQ_SIZE(BOOST_MULTI_INDEX_BA_SIZES)];
static std::size_t size_index(std::size_t n)
{
const std::size_t *bound=std::lower_bound(sizes,sizes+sizes_length,n);
if(bound==sizes+sizes_length)--bound;
return bound-sizes;
}
#define BOOST_MULTI_INDEX_BA_POSITION_CASE(z,n,_) \
case n:return hash%BOOST_PP_SEQ_ELEM(n,BOOST_MULTI_INDEX_BA_SIZES);
static std::size_t position(std::size_t hash,std::size_t size_index_)
{
/* Accelerate hash%sizes[size_index_] by replacing with a switch on
* hash%Ci expressions, each Ci a compile-time constant, which the
* compiler can implement without using integer division.
*/
switch(size_index_){
default: /* never used */
BOOST_PP_REPEAT(
BOOST_PP_SEQ_SIZE(BOOST_MULTI_INDEX_BA_SIZES),
BOOST_MULTI_INDEX_BA_POSITION_CASE,~)
}
}
private:
static const std::size_t sizes_length;
};
template<bool _>
const std::size_t bucket_array_base<_>::sizes[]={
BOOST_PP_SEQ_ENUM(BOOST_MULTI_INDEX_BA_SIZES)
};
template<bool _>
const std::size_t bucket_array_base<_>::sizes_length=
sizeof(bucket_array_base<_>::sizes)/
sizeof(bucket_array_base<_>::sizes[0]);
#undef BOOST_MULTI_INDEX_BA_POSITION_CASE
#undef BOOST_MULTI_INDEX_BA_SIZES
#undef BOOST_MULTI_INDEX_BA_SIZES_32BIT
template<typename Allocator>
class bucket_array:bucket_array_base<>
{
typedef bucket_array_base<> super;
typedef hashed_index_base_node_impl<
typename boost::detail::allocator::rebind_to<
Allocator,
char
>::type
> base_node_impl_type;
public:
typedef typename base_node_impl_type::base_pointer base_pointer;
typedef typename base_node_impl_type::pointer pointer;
bucket_array(const Allocator& al,pointer end_,std::size_t size_):
size_index_(super::size_index(size_)),
spc(al,super::sizes[size_index_]+1)
{
clear(end_);
}
std::size_t size()const
{
return super::sizes[size_index_];
}
std::size_t position(std::size_t hash)const
{
return super::position(hash,size_index_);
}
base_pointer begin()const{return buckets();}
base_pointer end()const{return buckets()+size();}
base_pointer at(std::size_t n)const{return buckets()+n;}
void clear(pointer end_)
{
for(base_pointer x=begin(),y=end();x!=y;++x)x->prior()=pointer(0);
end()->prior()=end_->prior()=end_;
end_->next()=end();
}
void swap(bucket_array& x)
{
std::swap(size_index_,x.size_index_);
spc.swap(x.spc);
}
private:
std::size_t size_index_;
auto_space<base_node_impl_type,Allocator> spc;
base_pointer buckets()const
{
return spc.data();
}
#if !defined(BOOST_MULTI_INDEX_DISABLE_SERIALIZATION)
friend class boost::serialization::access;
/* bucket_arrays do not emit any kind of serialization info. They are
* fed to Boost.Serialization as hashed index iterators need to track
* them during serialization.
*/
template<class Archive>
void serialize(Archive&,const unsigned int)
{
}
#endif
};
template<typename Allocator>
void swap(bucket_array<Allocator>& x,bucket_array<Allocator>& y)
{
x.swap(y);
}
} /* namespace multi_index::detail */
} /* namespace multi_index */
#if !defined(BOOST_MULTI_INDEX_DISABLE_SERIALIZATION)
/* bucket_arrays never get constructed directly by Boost.Serialization,
* as archives are always fed pointers to previously existent
* arrays. So, if this is called it means we are dealing with a
* somehow invalid archive.
*/
#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
namespace serialization{
#else
namespace multi_index{
namespace detail{
#endif
template<class Archive,typename Allocator>
inline void load_construct_data(
Archive&,boost::multi_index::detail::bucket_array<Allocator>*,
const unsigned int)
{
throw_exception(
archive::archive_exception(archive::archive_exception::other_exception));
}
#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
} /* namespace serialization */
#else
} /* namespace multi_index::detail */
} /* namespace multi_index */
#endif
#endif
} /* namespace boost */
#endif
@@ -0,0 +1,93 @@
/* Copyright 2003-2014 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_CONS_STDTUPLE_HPP
#define BOOST_MULTI_INDEX_DETAIL_CONS_STDTUPLE_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <boost/mpl/if.hpp>
#include <boost/tuple/tuple.hpp>
#include <tuple>
namespace boost{
namespace multi_index{
namespace detail{
/* std::tuple wrapper providing the cons-based interface of boost::tuple for
* composite_key interoperability.
*/
template<typename StdTuple,std::size_t N>
struct cons_stdtuple;
struct cons_stdtuple_ctor_terminal
{
typedef boost::tuples::null_type result_type;
template<typename StdTuple>
static result_type create(const StdTuple&)
{
return boost::tuples::null_type();
}
};
template<typename StdTuple,std::size_t N>
struct cons_stdtuple_ctor_normal
{
typedef cons_stdtuple<StdTuple,N> result_type;
static result_type create(const StdTuple& t)
{
return result_type(t);
}
};
template<typename StdTuple,std::size_t N=0>
struct cons_stdtuple_ctor:
boost::mpl::if_c<
N<std::tuple_size<StdTuple>::value,
cons_stdtuple_ctor_normal<StdTuple,N>,
cons_stdtuple_ctor_terminal
>::type
{};
template<typename StdTuple,std::size_t N>
struct cons_stdtuple
{
typedef typename std::tuple_element<N,StdTuple>::type head_type;
typedef cons_stdtuple_ctor<StdTuple,N+1> tail_ctor;
typedef typename tail_ctor::result_type tail_type;
cons_stdtuple(const StdTuple& t_):t(t_){}
const head_type& get_head()const{return std::get<N>(t);}
tail_type get_tail()const{return tail_ctor::create(t);}
const StdTuple& t;
};
template<typename StdTuple>
typename cons_stdtuple_ctor<StdTuple>::result_type
make_cons_stdtuple(const StdTuple& t)
{
return cons_stdtuple_ctor<StdTuple>::create(t);
}
} /* namespace multi_index::detail */
} /* namespace multi_index */
} /* namespace boost */
#endif
@@ -0,0 +1,52 @@
/* Copyright 2003-2013 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_CONVERTER_HPP
#define BOOST_MULTI_INDEX_DETAIL_CONVERTER_HPP
#if defined(_MSC_VER)
#pragma once
#endif
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<typename MultiIndexContainer,typename Index>
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
@@ -0,0 +1,142 @@
/* Copyright 2003-2015 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_COPY_MAP_HPP
#define BOOST_MULTI_INDEX_DETAIL_COPY_MAP_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <algorithm>
#include <boost/detail/no_exceptions_support.hpp>
#include <boost/multi_index/detail/auto_space.hpp>
#include <boost/multi_index/detail/raw_ptr.hpp>
#include <boost/noncopyable.hpp>
#include <cstddef>
#include <functional>
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 <typename Node>
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<Node>& x)const
{
return std::less<Node*>()(first,x.first);
}
};
template <typename Node,typename Allocator>
class copy_map:private noncopyable
{
public:
typedef const copy_map_entry<Node>* 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;i<n;++i){
boost::detail::allocator::destroy(&(spc.data()+i)->second->value());
deallocate((spc.data()+i)->second);
}
}
}
const_iterator begin()const{return raw_ptr<const_iterator>(spc.data());}
const_iterator end()const{return raw_ptr<const_iterator>(spc.data()+n);}
void clone(Node* node)
{
(spc.data()+n)->first=node;
(spc.data()+n)->second=raw_ptr<Node*>(al_.allocate(1));
BOOST_TRY{
boost::detail::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(
raw_ptr<copy_map_entry<Node>*>(spc.data()),
raw_ptr<copy_map_entry<Node>*>(spc.data())+size_);
}
}
Node* find(Node* node)const
{
if(node==header_org_)return header_cpy_;
return std::lower_bound(
begin(),end(),copy_map_entry<Node>(node,0))->second;
}
void release()
{
released=true;
}
private:
typedef typename boost::detail::allocator::rebind_to<
Allocator,Node
>::type allocator_type;
typedef typename allocator_type::pointer allocator_pointer;
allocator_type al_;
std::size_t size_;
auto_space<copy_map_entry<Node>,Allocator> spc;
std::size_t n;
Node* header_org_;
Node* header_cpy_;
bool released;
void deallocate(Node* node)
{
al_.deallocate(static_cast<allocator_pointer>(node),1);
}
};
} /* namespace multi_index::detail */
} /* namespace multi_index */
} /* namespace boost */
#endif
@@ -0,0 +1,34 @@
/* Copyright 2003-2013 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_DO_NOT_COPY_ELEMENTS_TAG_HPP
#define BOOST_MULTI_INDEX_DETAIL_DO_NOT_COPY_ELEMENTS_TAG_HPP
#if defined(_MSC_VER)
#pragma once
#endif
namespace boost{
namespace multi_index{
namespace detail{
/* Used to mark a special ctor variant that copies the internal objects of
* a container but not its elements.
*/
struct do_not_copy_elements_tag{};
} /* namespace multi_index::detail */
} /* namespace multi_index */
} /* namespace boost */
#endif
@@ -0,0 +1,120 @@
/* Copyright 2003-2013 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_DUPLICATES_ITERATOR_HPP
#define BOOST_MULTI_INDEX_DETAIL_DUPLICATES_ITERATOR_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <cstddef>
#include <iterator>
namespace boost{
namespace multi_index{
namespace detail{
/* duplicates_operator is given a range of ordered elements and
* passes only over those which are duplicated.
*/
template<typename Node,typename Predicate>
class duplicates_iterator
{
public:
typedef typename Node::value_type value_type;
typedef std::ptrdiff_t difference_type;
typedef const typename Node::value_type* pointer;
typedef const typename Node::value_type& reference;
typedef std::forward_iterator_tag iterator_category;
duplicates_iterator(Node* node_,Node* end_,Predicate pred_):
node(node_),begin_chunk(0),end(end_),pred(pred_)
{
advance();
}
duplicates_iterator(Node* end_,Predicate pred_):
node(end_),begin_chunk(end_),end(end_),pred(pred_)
{
}
reference operator*()const
{
return node->value();
}
pointer operator->()const
{
return &node->value();
}
duplicates_iterator& operator++()
{
Node::increment(node);
sync();
return *this;
}
duplicates_iterator operator++(int)
{
duplicates_iterator tmp(*this);
++(*this);
return tmp;
}
Node* get_node()const{return node;}
private:
void sync()
{
if(node!=end&&pred(begin_chunk->value(),node->value()))advance();
}
void advance()
{
for(Node* node2=node;node!=end;node=node2){
Node::increment(node2);
if(node2!=end&&!pred(node->value(),node2->value()))break;
}
begin_chunk=node;
}
Node* node;
Node* begin_chunk;
Node* end;
Predicate pred;
};
template<typename Node,typename Predicate>
bool operator==(
const duplicates_iterator<Node,Predicate>& x,
const duplicates_iterator<Node,Predicate>& y)
{
return x.get_node()==y.get_node();
}
template<typename Node,typename Predicate>
bool operator!=(
const duplicates_iterator<Node,Predicate>& x,
const duplicates_iterator<Node,Predicate>& y)
{
return !(x==y);
}
} /* namespace multi_index::detail */
} /* namespace multi_index */
} /* namespace boost */
#endif
@@ -0,0 +1,42 @@
/* Copyright 2003-2013 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_HAS_TAG_HPP
#define BOOST_MULTI_INDEX_DETAIL_HAS_TAG_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <boost/mpl/contains.hpp>
namespace boost{
namespace multi_index{
namespace detail{
/* determines whether an index type has a given tag in its tag list */
template<typename Tag>
struct has_tag
{
template<typename Index>
struct apply:mpl::contains<BOOST_DEDUCED_TYPENAME Index::tag_list,Tag>
{
};
};
} /* namespace multi_index::detail */
} /* namespace multi_index */
} /* namespace boost */
#endif
@@ -0,0 +1,105 @@
/* Copyright 2003-2013 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_HASH_INDEX_ARGS_HPP
#define BOOST_MULTI_INDEX_DETAIL_HASH_INDEX_ARGS_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <boost/functional/hash.hpp>
#include <boost/mpl/aux_/na.hpp>
#include <boost/mpl/eval_if.hpp>
#include <boost/mpl/identity.hpp>
#include <boost/mpl/if.hpp>
#include <boost/multi_index/tag.hpp>
#include <boost/static_assert.hpp>
#include <boost/type_traits/is_same.hpp>
#include <functional>
namespace boost{
namespace multi_index{
namespace detail{
/* Hashed index specifiers can be instantiated in two forms:
*
* (hashed_unique|hashed_non_unique)<
* KeyFromValue,
* Hash=boost::hash<KeyFromValue::result_type>,
* Pred=std::equal_to<KeyFromValue::result_type> >
* (hashed_unique|hashed_non_unique)<
* TagList,
* KeyFromValue,
* Hash=boost::hash<KeyFromValue::result_type>,
* Pred=std::equal_to<KeyFromValue::result_type> >
*
* hashed_index_args implements the machinery to accept this
* argument-dependent polymorphism.
*/
template<typename KeyFromValue>
struct index_args_default_hash
{
typedef ::boost::hash<typename KeyFromValue::result_type> type;
};
template<typename KeyFromValue>
struct index_args_default_pred
{
typedef std::equal_to<typename KeyFromValue::result_type> type;
};
template<typename Arg1,typename Arg2,typename Arg3,typename Arg4>
struct hashed_index_args
{
typedef is_tag<Arg1> 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_hash_type;
typedef typename mpl::eval_if<
mpl::is_na<supplied_hash_type>,
index_args_default_hash<key_from_value_type>,
mpl::identity<supplied_hash_type>
>::type hash_type;
typedef typename mpl::if_<
full_form,
Arg4,
Arg3>::type supplied_pred_type;
typedef typename mpl::eval_if<
mpl::is_na<supplied_pred_type>,
index_args_default_pred<key_from_value_type>,
mpl::identity<supplied_pred_type>
>::type pred_type;
BOOST_STATIC_ASSERT(is_tag<tag_list_type>::value);
BOOST_STATIC_ASSERT(!mpl::is_na<key_from_value_type>::value);
BOOST_STATIC_ASSERT(!mpl::is_na<hash_type>::value);
BOOST_STATIC_ASSERT(!mpl::is_na<pred_type>::value);
};
} /* namespace multi_index::detail */
} /* namespace multi_index */
} /* namespace boost */
#endif
@@ -0,0 +1,166 @@
/* Copyright 2003-2014 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_HASH_INDEX_ITERATOR_HPP
#define BOOST_MULTI_INDEX_DETAIL_HASH_INDEX_ITERATOR_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <boost/operators.hpp>
#if !defined(BOOST_MULTI_INDEX_DISABLE_SERIALIZATION)
#include <boost/serialization/nvp.hpp>
#include <boost/serialization/split_member.hpp>
#include <boost/serialization/version.hpp>
#endif
namespace boost{
namespace multi_index{
namespace detail{
/* Iterator class for hashed indices.
*/
struct hashed_index_global_iterator_tag{};
struct hashed_index_local_iterator_tag{};
template<typename Node,typename BucketArray,typename Category>
class hashed_index_iterator:
public forward_iterator_helper<
hashed_index_iterator<Node,BucketArray,Category>,
typename Node::value_type,
std::ptrdiff_t,
const typename Node::value_type*,
const typename Node::value_type&>
{
public:
/* coverity[uninit_ctor]: suppress warning */
hashed_index_iterator(){}
hashed_index_iterator(Node* node_):node(node_){}
const typename Node::value_type& operator*()const
{
return node->value();
}
hashed_index_iterator& operator++()
{
this->increment(Category());
return *this;
}
#if !defined(BOOST_MULTI_INDEX_DISABLE_SERIALIZATION)
/* Serialization. As for why the following is public,
* see explanation in safe_mode_iterator notes in safe_mode.hpp.
*/
BOOST_SERIALIZATION_SPLIT_MEMBER()
typedef typename Node::base_type node_base_type;
template<class Archive>
void save(Archive& ar,const unsigned int)const
{
node_base_type* bnode=node;
ar<<serialization::make_nvp("pointer",bnode);
}
template<class Archive>
void load(Archive& ar,const unsigned int version)
{
load(ar,version,Category());
}
template<class Archive>
void load(
Archive& ar,const unsigned int version,hashed_index_global_iterator_tag)
{
node_base_type* bnode;
ar>>serialization::make_nvp("pointer",bnode);
node=static_cast<Node*>(bnode);
if(version<1){
BucketArray* throw_away; /* consume unused ptr */
ar>>serialization::make_nvp("pointer",throw_away);
}
}
template<class Archive>
void load(
Archive& ar,const unsigned int version,hashed_index_local_iterator_tag)
{
node_base_type* bnode;
ar>>serialization::make_nvp("pointer",bnode);
node=static_cast<Node*>(bnode);
if(version<1){
BucketArray* buckets;
ar>>serialization::make_nvp("pointer",buckets);
if(buckets&&node&&node->impl()==buckets->end()->prior()){
/* end local_iterators used to point to end node, now they are null */
node=0;
}
}
}
#endif
/* get_node is not to be used by the user */
typedef Node node_type;
Node* get_node()const{return node;}
private:
void increment(hashed_index_global_iterator_tag)
{
Node::increment(node);
}
void increment(hashed_index_local_iterator_tag)
{
Node::increment_local(node);
}
Node* node;
};
template<typename Node,typename BucketArray,typename Category>
bool operator==(
const hashed_index_iterator<Node,BucketArray,Category>& x,
const hashed_index_iterator<Node,BucketArray,Category>& y)
{
return x.get_node()==y.get_node();
}
} /* namespace multi_index::detail */
} /* namespace multi_index */
#if !defined(BOOST_MULTI_INDEX_DISABLE_SERIALIZATION)
/* class version = 1 : hashed_index_iterator does no longer serialize a bucket
* array pointer.
*/
namespace serialization {
template<typename Node,typename BucketArray,typename Category>
struct version<
boost::multi_index::detail::hashed_index_iterator<Node,BucketArray,Category>
>
{
BOOST_STATIC_CONSTANT(int,value=1);
};
} /* namespace serialization */
#endif
} /* namespace boost */
#endif
@@ -0,0 +1,778 @@
/* Copyright 2003-2015 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_HASH_INDEX_NODE_HPP
#define BOOST_MULTI_INDEX_DETAIL_HASH_INDEX_NODE_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <boost/detail/allocator_utilities.hpp>
#include <boost/multi_index/detail/raw_ptr.hpp>
#include <utility>
namespace boost{
namespace multi_index{
namespace detail{
/* Certain C++ requirements on unordered associative containers (see LWG issue
* #579) imply a data structure where nodes are linked in a single list, which
* in its turn forces implementors to add additional overhed per node to
* associate each with its corresponding bucket. Others resort to storing hash
* values, we use an alternative structure providing unconditional O(1)
* manipulation, even in situations of unfair hash distribution, plus some
* lookup speedups. For unique indices we maintain a doubly linked list of
* nodes except that if N is the first node of a bucket its associated
* bucket node is embedded between N and the preceding node in the following
* manner:
*
* +---+ +---+ +---+ +---+
* <--+ |<--+ | <--+ |<--+ |
* ... | B0| | B1| ... | B1| | B2| ...
* | |-+ | +--> | |-+ | +-->
* +-+-+ | +---+ +-+-+ | +---+
* | ^ | ^
* | | | |
* | +-+ | +-+
* | | | |
* v | v |
* --+---+---+---+-- --+---+---+---+--
* ... | | B1| | ... | | B2| | ...
* --+---+---+---+-- --+---+---+---+--
*
*
* The fist and last nodes of buckets can be checked with
*
* first node of a bucket: Npn != N
* last node of a bucket: Nnp != N
*
* (n and p short for ->next(), ->prior(), bucket nodes have prior pointers
* only). Pure insert and erase (without lookup) can be unconditionally done
* in O(1).
* For non-unique indices we add the following additional complexity: when
* there is a group of 3 or more equivalent elements, they are linked as
* follows:
*
* +-----------------------+
* | v
* +---+ | +---+ +---+ +---+
* | | +-+ | | |<--+ |
* | F | | S | ... | P | | L |
* | +-->| | | +-+ | |
* +---+ +---+ +---+ | +---+
* ^ |
* +-----------------------+
*
* F, S, P and L are the first, second, penultimate and last node in the
* group, respectively (S and P can coincide if the group has size 3.) This
* arrangement is used to skip equivalent elements in O(1) when doing lookup,
* while preserving O(1) insert/erase. The following invariants identify
* special positions (some of the operations have to be carefully implemented
* as Xnn is not valid if Xn points to a bucket):
*
* first node of a bucket: Npnp == N
* last node of a bucket: Nnpp == N
* first node of a group: Nnp != N && Nnppn == N
* second node of a group: Npn != N && Nppnn == N
* n-1 node of a group: Nnp != N && Nnnpp == N
* last node of a group: Npn != N && Npnnp == N
*
* The memory overhead is one pointer per bucket plus two pointers per node,
* probably unbeatable. The resulting structure is bidirectonally traversable,
* though currently we are just providing forward iteration.
*/
template<typename Allocator>
struct hashed_index_node_impl;
/* half-header (only prior() pointer) to use for the bucket array */
template<typename Allocator>
struct hashed_index_base_node_impl
{
typedef typename
boost::detail::allocator::rebind_to<
Allocator,hashed_index_base_node_impl
>::type::pointer base_pointer;
typedef typename
boost::detail::allocator::rebind_to<
Allocator,hashed_index_base_node_impl
>::type::const_pointer const_base_pointer;
typedef typename
boost::detail::allocator::rebind_to<
Allocator,
hashed_index_node_impl<Allocator>
>::type::pointer pointer;
typedef typename
boost::detail::allocator::rebind_to<
Allocator,
hashed_index_node_impl<Allocator>
>::type::const_pointer const_pointer;
pointer& prior(){return prior_;}
pointer prior()const{return prior_;}
private:
pointer prior_;
};
/* full header (prior() and next()) for the nodes */
template<typename Allocator>
struct hashed_index_node_impl:hashed_index_base_node_impl<Allocator>
{
private:
typedef hashed_index_base_node_impl<Allocator> super;
public:
typedef typename super::base_pointer base_pointer;
typedef typename super::const_base_pointer const_base_pointer;
typedef typename super::pointer pointer;
typedef typename super::const_pointer const_pointer;
base_pointer& next(){return next_;}
base_pointer next()const{return next_;}
static pointer pointer_from(base_pointer x)
{
return static_cast<pointer>(
static_cast<hashed_index_node_impl*>(
raw_ptr<super*>(x)));
}
static base_pointer base_pointer_from(pointer x)
{
return static_cast<base_pointer>(
raw_ptr<hashed_index_node_impl*>(x));
}
private:
base_pointer next_;
};
/* Boost.MultiIndex requires machinery to reverse unlink operations. A simple
* way to make a pointer-manipulation function undoable is to templatize
* its internal pointer assignments with a functor that, besides doing the
* assignment, keeps track of the original pointer values and can later undo
* the operations in reverse order.
*/
struct default_assigner
{
template<typename T> void operator()(T& x,const T& val){x=val;}
};
template<typename Node>
struct unlink_undo_assigner
{
typedef typename Node::base_pointer base_pointer;
typedef typename Node::pointer pointer;
unlink_undo_assigner():pointer_track_count(0),base_pointer_track_count(0){}
void operator()(pointer& x,pointer val)
{
pointer_tracks[pointer_track_count].x=&x;
pointer_tracks[pointer_track_count++].val=x;
x=val;
}
void operator()(base_pointer& x,base_pointer val)
{
base_pointer_tracks[base_pointer_track_count].x=&x;
base_pointer_tracks[base_pointer_track_count++].val=x;
x=val;
}
void operator()() /* undo op */
{
/* in the absence of aliasing, restitution order is immaterial */
while(pointer_track_count--){
*(pointer_tracks[pointer_track_count].x)=
pointer_tracks[pointer_track_count].val;
}
while(base_pointer_track_count--){
*(base_pointer_tracks[base_pointer_track_count].x)=
base_pointer_tracks[base_pointer_track_count].val;
}
}
struct pointer_track {pointer* x; pointer val;};
struct base_pointer_track{base_pointer* x; base_pointer val;};
/* We know the maximum number of pointer and base pointer assignments that
* the two unlink versions do, so we can statically reserve the needed
* storage.
*/
pointer_track pointer_tracks[3];
int pointer_track_count;
base_pointer_track base_pointer_tracks[2];
int base_pointer_track_count;
};
/* algorithmic stuff for unique and non-unique variants */
struct hashed_unique_tag{};
struct hashed_non_unique_tag{};
template<typename Node,typename Category>
struct hashed_index_node_alg;
template<typename Node>
struct hashed_index_node_alg<Node,hashed_unique_tag>
{
typedef typename Node::base_pointer base_pointer;
typedef typename Node::const_base_pointer const_base_pointer;
typedef typename Node::pointer pointer;
typedef typename Node::const_pointer const_pointer;
static bool is_first_of_bucket(pointer x)
{
return x->prior()->next()!=base_pointer_from(x);
}
static pointer after(pointer x)
{
return is_last_of_bucket(x)?x->next()->prior():pointer_from(x->next());
}
static pointer after_local(pointer x)
{
return is_last_of_bucket(x)?pointer(0):pointer_from(x->next());
}
static pointer next_to_inspect(pointer x)
{
return is_last_of_bucket(x)?pointer(0):pointer_from(x->next());
}
static void link(pointer x,base_pointer buc,pointer end)
{
if(buc->prior()==pointer(0)){ /* empty bucket */
x->prior()=end->prior();
x->next()=end->prior()->next();
x->prior()->next()=buc;
buc->prior()=x;
end->prior()=x;
}
else{
x->prior()=buc->prior()->prior();
x->next()=base_pointer_from(buc->prior());
buc->prior()=x;
x->next()->prior()=x;
}
}
static void unlink(pointer x)
{
default_assigner assign;
unlink(x,assign);
}
typedef unlink_undo_assigner<Node> unlink_undo;
template<typename Assigner>
static void unlink(pointer x,Assigner& assign)
{
if(is_first_of_bucket(x)){
if(is_last_of_bucket(x)){
assign(x->prior()->next()->prior(),pointer(0));
assign(x->prior()->next(),x->next());
assign(x->next()->prior()->prior(),x->prior());
}
else{
assign(x->prior()->next()->prior(),pointer_from(x->next()));
assign(x->next()->prior(),x->prior());
}
}
else if(is_last_of_bucket(x)){
assign(x->prior()->next(),x->next());
assign(x->next()->prior()->prior(),x->prior());
}
else{
assign(x->prior()->next(),x->next());
assign(x->next()->prior(),x->prior());
}
}
/* used only at rehashing */
static void append(pointer x,pointer end)
{
x->prior()=end->prior();
x->next()=end->prior()->next();
x->prior()->next()=base_pointer_from(x);
end->prior()=x;
}
static bool unlink_last(pointer end)
{
/* returns true iff bucket is emptied */
pointer x=end->prior();
if(x->prior()->next()==base_pointer_from(x)){
x->prior()->next()=x->next();
end->prior()=x->prior();
return false;
}
else{
x->prior()->next()->prior()=pointer(0);
x->prior()->next()=x->next();
end->prior()=x->prior();
return true;
}
}
private:
static pointer pointer_from(base_pointer x)
{
return Node::pointer_from(x);
}
static base_pointer base_pointer_from(pointer x)
{
return Node::base_pointer_from(x);
}
static bool is_last_of_bucket(pointer x)
{
return x->next()->prior()!=x;
}
};
template<typename Node>
struct hashed_index_node_alg<Node,hashed_non_unique_tag>
{
typedef typename Node::base_pointer base_pointer;
typedef typename Node::const_base_pointer const_base_pointer;
typedef typename Node::pointer pointer;
typedef typename Node::const_pointer const_pointer;
static bool is_first_of_bucket(pointer x)
{
return x->prior()->next()->prior()==x;
}
static bool is_first_of_group(pointer x)
{
return
x->next()->prior()!=x&&
x->next()->prior()->prior()->next()==base_pointer_from(x);
}
static pointer after(pointer x)
{
if(x->next()->prior()==x)return pointer_from(x->next());
if(x->next()->prior()->prior()==x)return x->next()->prior();
if(x->next()->prior()->prior()->next()==base_pointer_from(x))
return pointer_from(x->next());
return pointer_from(x->next())->next()->prior();
}
static pointer after_local(pointer x)
{
if(x->next()->prior()==x)return pointer_from(x->next());
if(x->next()->prior()->prior()==x)return pointer(0);
if(x->next()->prior()->prior()->next()==base_pointer_from(x))
return pointer_from(x->next());
return pointer_from(x->next())->next()->prior();
}
static pointer next_to_inspect(pointer x)
{
if(x->next()->prior()==x)return pointer_from(x->next());
if(x->next()->prior()->prior()==x)return pointer(0);
if(x->next()->prior()->next()->prior()!=x->next()->prior())
return pointer(0);
return pointer_from(x->next()->prior()->next());
}
static void link(pointer x,base_pointer buc,pointer end)
{
if(buc->prior()==pointer(0)){ /* empty bucket */
x->prior()=end->prior();
x->next()=end->prior()->next();
x->prior()->next()=buc;
buc->prior()=x;
end->prior()=x;
}
else{
x->prior()=buc->prior()->prior();
x->next()=base_pointer_from(buc->prior());
buc->prior()=x;
x->next()->prior()=x;
}
};
static void link(pointer x,pointer first,pointer last)
{
x->prior()=first->prior();
x->next()=base_pointer_from(first);
if(is_first_of_bucket(first)){
x->prior()->next()->prior()=x;
}
else{
x->prior()->next()=base_pointer_from(x);
}
if(first==last){
last->prior()=x;
}
else if(first->next()==base_pointer_from(last)){
first->prior()=last;
first->next()=base_pointer_from(x);
}
else{
pointer second=pointer_from(first->next()),
lastbutone=last->prior();
second->prior()=first;
first->prior()=last;
lastbutone->next()=base_pointer_from(x);
}
}
static void unlink(pointer x)
{
default_assigner assign;
unlink(x,assign);
}
typedef unlink_undo_assigner<Node> unlink_undo;
template<typename Assigner>
static void unlink(pointer x,Assigner& assign)
{
if(x->prior()->next()==base_pointer_from(x)){
if(x->next()->prior()==x){
left_unlink(x,assign);
right_unlink(x,assign);
}
else if(x->next()->prior()->prior()==x){ /* last of bucket */
left_unlink(x,assign);
right_unlink_last_of_bucket(x,assign);
}
else if(x->next()->prior()->prior()->next()==
base_pointer_from(x)){ /* first of group size */
left_unlink(x,assign);
right_unlink_first_of_group(x,assign);
}
else{ /* n-1 of group */
unlink_last_but_one_of_group(x,assign);
}
}
else if(x->prior()->next()->prior()==x){ /* first of bucket */
if(x->next()->prior()==x){
left_unlink_first_of_bucket(x,assign);
right_unlink(x,assign);
}
else if(x->next()->prior()->prior()==x){ /* last of bucket */
assign(x->prior()->next()->prior(),pointer(0));
assign(x->prior()->next(),x->next());
assign(x->next()->prior()->prior(),x->prior());
}
else{ /* first of group */
left_unlink_first_of_bucket(x,assign);
right_unlink_first_of_group(x,assign);
}
}
else if(x->next()->prior()->prior()==x){ /* last of group and bucket */
left_unlink_last_of_group(x,assign);
right_unlink_last_of_bucket(x,assign);
}
else if(pointer_from(x->prior()->prior()->next())
->next()==base_pointer_from(x)){ /* second of group */
unlink_second_of_group(x,assign);
}
else{ /* last of group, ~(last of bucket) */
left_unlink_last_of_group(x,assign);
right_unlink(x,assign);
}
}
/* used only at rehashing */
static void link_range(
pointer first,pointer last,base_pointer buc,pointer cend)
{
if(buc->prior()==pointer(0)){ /* empty bucket */
first->prior()=cend->prior();
last->next()=cend->prior()->next();
first->prior()->next()=buc;
buc->prior()=first;
cend->prior()=last;
}
else{
first->prior()=buc->prior()->prior();
last->next()=base_pointer_from(buc->prior());
buc->prior()=first;
last->next()->prior()=last;
}
}
static void append_range(pointer first,pointer last,pointer cend)
{
first->prior()=cend->prior();
last->next()=cend->prior()->next();
first->prior()->next()=base_pointer_from(first);
cend->prior()=last;
}
static std::pair<pointer,bool> unlink_last_group(pointer end)
{
/* returns first of group true iff bucket is emptied */
pointer x=end->prior();
if(x->prior()->next()==base_pointer_from(x)){
x->prior()->next()=x->next();
end->prior()=x->prior();
return std::make_pair(x,false);
}
else if(x->prior()->next()->prior()==x){
x->prior()->next()->prior()=pointer(0);
x->prior()->next()=x->next();
end->prior()=x->prior();
return std::make_pair(x,true);
}
else{
pointer y=pointer_from(x->prior()->next());
if(y->prior()->next()==base_pointer_from(y)){
y->prior()->next()=x->next();
end->prior()=y->prior();
return std::make_pair(y,false);
}
else{
y->prior()->next()->prior()=pointer(0);
y->prior()->next()=x->next();
end->prior()=y->prior();
return std::make_pair(y,true);
}
}
}
static void unlink_range(pointer first,pointer last)
{
if(is_first_of_bucket(first)){
if(is_last_of_bucket(last)){
first->prior()->next()->prior()=pointer(0);
first->prior()->next()=last->next();
last->next()->prior()->prior()=first->prior();
}
else{
first->prior()->next()->prior()=pointer_from(last->next());
last->next()->prior()=first->prior();
}
}
else if(is_last_of_bucket(last)){
first->prior()->next()=last->next();
last->next()->prior()->prior()=first->prior();
}
else{
first->prior()->next()=last->next();
last->next()->prior()=first->prior();
}
}
private:
static pointer pointer_from(base_pointer x)
{
return Node::pointer_from(x);
}
static base_pointer base_pointer_from(pointer x)
{
return Node::base_pointer_from(x);
}
static bool is_last_of_bucket(pointer x)
{
return x->next()->prior()->prior()==x;
}
template<typename Assigner>
static void left_unlink(pointer x,Assigner& assign)
{
assign(x->prior()->next(),x->next());
}
template<typename Assigner>
static void right_unlink(pointer x,Assigner& assign)
{
assign(x->next()->prior(),x->prior());
}
template<typename Assigner>
static void left_unlink_first_of_bucket(pointer x,Assigner& assign)
{
assign(x->prior()->next()->prior(),pointer_from(x->next()));
}
template<typename Assigner>
static void right_unlink_last_of_bucket(pointer x,Assigner& assign)
{
assign(x->next()->prior()->prior(),x->prior());
}
template<typename Assigner>
static void right_unlink_first_of_group(pointer x,Assigner& assign)
{
pointer second=pointer_from(x->next()),
last=second->prior(),
lastbutone=last->prior();
if(second==lastbutone){
assign(second->next(),base_pointer_from(last));
assign(second->prior(),x->prior());
}
else{
assign(lastbutone->next(),base_pointer_from(second));
assign(second->next()->prior(),last);
assign(second->prior(),x->prior());
}
}
template<typename Assigner>
static void left_unlink_last_of_group(pointer x,Assigner& assign)
{
pointer lastbutone=x->prior(),
first=pointer_from(lastbutone->next()),
second=pointer_from(first->next());
if(lastbutone==second){
assign(lastbutone->prior(),first);
assign(lastbutone->next(),x->next());
}
else{
assign(second->prior(),lastbutone);
assign(lastbutone->prior()->next(),base_pointer_from(first));
assign(lastbutone->next(),x->next());
}
}
template<typename Assigner>
static void unlink_last_but_one_of_group(pointer x,Assigner& assign)
{
pointer first=pointer_from(x->next()),
second=pointer_from(first->next()),
last=second->prior();
if(second==x){
assign(last->prior(),first);
assign(first->next(),base_pointer_from(last));
}
else{
assign(last->prior(),x->prior());
assign(x->prior()->next(),base_pointer_from(first));
}
}
template<typename Assigner>
static void unlink_second_of_group(pointer x,Assigner& assign)
{
pointer last=x->prior(),
lastbutone=last->prior(),
first=pointer_from(lastbutone->next());
if(lastbutone==x){
assign(first->next(),base_pointer_from(last));
assign(last->prior(),first);
}
else{
assign(first->next(),x->next());
assign(x->next()->prior(),last);
}
}
};
template<typename Super>
struct hashed_index_node_trampoline:
hashed_index_node_impl<
typename boost::detail::allocator::rebind_to<
typename Super::allocator_type,
char
>::type
>
{
typedef typename boost::detail::allocator::rebind_to<
typename Super::allocator_type,
char
>::type impl_allocator_type;
typedef hashed_index_node_impl<impl_allocator_type> impl_type;
};
template<typename Super,typename Category>
struct hashed_index_node:
Super,hashed_index_node_trampoline<Super>
{
private:
typedef hashed_index_node_trampoline<Super> trampoline;
public:
typedef typename trampoline::impl_type impl_type;
typedef hashed_index_node_alg<
impl_type,Category> node_alg;
typedef typename trampoline::base_pointer impl_base_pointer;
typedef typename trampoline::const_base_pointer const_impl_base_pointer;
typedef typename trampoline::pointer impl_pointer;
typedef typename trampoline::const_pointer const_impl_pointer;
impl_pointer& prior(){return trampoline::prior();}
impl_pointer prior()const{return trampoline::prior();}
impl_base_pointer& next(){return trampoline::next();}
impl_base_pointer next()const{return trampoline::next();}
impl_pointer impl()
{
return static_cast<impl_pointer>(
static_cast<impl_type*>(static_cast<trampoline*>(this)));
}
const_impl_pointer impl()const
{
return static_cast<const_impl_pointer>(
static_cast<const impl_type*>(static_cast<const trampoline*>(this)));
}
static hashed_index_node* from_impl(impl_pointer x)
{
return
static_cast<hashed_index_node*>(
static_cast<trampoline*>(
raw_ptr<impl_type*>(x)));
}
static const hashed_index_node* from_impl(const_impl_pointer x)
{
return
static_cast<const hashed_index_node*>(
static_cast<const trampoline*>(
raw_ptr<const impl_type*>(x)));
}
/* interoperability with hashed_index_iterator */
static void increment(hashed_index_node*& x)
{
x=from_impl(node_alg::after(x->impl()));
}
static void increment_local(hashed_index_node*& x)
{
x=from_impl(node_alg::after_local(x->impl()));
}
};
} /* namespace multi_index::detail */
} /* namespace multi_index */
} /* namespace boost */
#endif
@@ -0,0 +1,50 @@
/* Copyright 2003-2008 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_HEADER_HOLDER_HPP
#define BOOST_MULTI_INDEX_DETAIL_HEADER_HOLDER_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/noncopyable.hpp>
namespace boost{
namespace multi_index{
namespace detail{
/* A utility class 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<typename NodeTypePtr,typename Final>
struct header_holder:private noncopyable
{
header_holder():member(final().allocate_node()){}
~header_holder(){final().deallocate_node(&*member);}
NodeTypePtr member;
private:
Final& final(){return *static_cast<Final*>(this);}
};
} /* namespace multi_index::detail */
} /* namespace multi_index */
} /* namespace boost */
#endif
@@ -0,0 +1,18 @@
/* Copyright 2003-2016 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#include <boost/config.hpp>
#if defined(BOOST_GCC)&&(BOOST_GCC>=4*10000+6*100)
#if !defined(BOOST_MULTI_INDEX_DETAIL_RESTORE_WSTRICT_ALIASING)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#else
#pragma GCC diagnostic pop
#endif
#endif
@@ -0,0 +1,293 @@
/* Copyright 2003-2014 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_INDEX_BASE_HPP
#define BOOST_MULTI_INDEX_DETAIL_INDEX_BASE_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <boost/detail/allocator_utilities.hpp>
#include <boost/detail/no_exceptions_support.hpp>
#include <boost/detail/workaround.hpp>
#include <boost/move/core.hpp>
#include <boost/move/utility.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/multi_index/detail/copy_map.hpp>
#include <boost/multi_index/detail/do_not_copy_elements_tag.hpp>
#include <boost/multi_index/detail/node_type.hpp>
#include <boost/multi_index/detail/vartempl_support.hpp>
#include <boost/multi_index_container_fwd.hpp>
#include <boost/tuple/tuple.hpp>
#include <utility>
#if !defined(BOOST_MULTI_INDEX_DISABLE_SERIALIZATION)
#include <boost/multi_index/detail/index_loader.hpp>
#include <boost/multi_index/detail/index_saver.hpp>
#endif
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.)
*/
struct lvalue_tag{};
struct rvalue_tag{};
struct emplaced_tag{};
template<typename Value,typename IndexSpecifierList,typename Allocator>
class index_base
{
protected:
typedef index_node_base<Value,Allocator> 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 typename
boost::detail::allocator::rebind_to<
Allocator,
typename Allocator::value_type
>::type 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<
final_node_type,
final_allocator_type> copy_map_type;
#if !defined(BOOST_MULTI_INDEX_DISABLE_SERIALIZATION)
typedef index_saver<
node_type,
final_allocator_type> index_saver_type;
typedef index_loader<
node_type,
final_node_type,
final_allocator_type> index_loader_type;
#endif
private:
typedef Value value_type;
protected:
explicit index_base(const ctor_args_list&,const Allocator&){}
index_base(
const index_base<Value,IndexSpecifierList,Allocator>&,
do_not_copy_elements_tag)
{}
void copy_(
const index_base<Value,IndexSpecifierList,Allocator>&,const copy_map_type&)
{}
final_node_type* insert_(const value_type& v,final_node_type*& x,lvalue_tag)
{
x=final().allocate_node();
BOOST_TRY{
boost::detail::allocator::construct(&x->value(),v);
}
BOOST_CATCH(...){
final().deallocate_node(x);
BOOST_RETHROW;
}
BOOST_CATCH_END
return x;
}
final_node_type* insert_(const value_type& v,final_node_type*& x,rvalue_tag)
{
x=final().allocate_node();
BOOST_TRY{
/* This shoud have used a modified, T&&-compatible version of
* boost::detail::allocator::construct, but
* <boost/detail/allocator_utilities.hpp> is too old and venerable to
* mess with; besides, it is a general internal utility and the imperfect
* perfect forwarding emulation of Boost.Move might break other libs.
*/
new (&x->value()) value_type(boost::move(const_cast<value_type&>(v)));
}
BOOST_CATCH(...){
final().deallocate_node(x);
BOOST_RETHROW;
}
BOOST_CATCH_END
return x;
}
final_node_type* insert_(const value_type&,final_node_type*& x,emplaced_tag)
{
return x;
}
final_node_type* insert_(
const value_type& v,node_type*,final_node_type*& x,lvalue_tag)
{
return insert_(v,x,lvalue_tag());
}
final_node_type* insert_(
const value_type& v,node_type*,final_node_type*& x,rvalue_tag)
{
return insert_(v,x,rvalue_tag());
}
final_node_type* insert_(
const value_type&,node_type*,final_node_type*& x,emplaced_tag)
{
return x;
}
void erase_(node_type* x)
{
boost::detail::allocator::destroy(&x->value());
}
void delete_node_(node_type* x)
{
boost::detail::allocator::destroy(&x->value());
}
void clear_(){}
void swap_(index_base<Value,IndexSpecifierList,Allocator>&){}
void swap_elements_(index_base<Value,IndexSpecifierList,Allocator>&){}
bool replace_(const value_type& v,node_type* x,lvalue_tag)
{
x->value()=v;
return true;
}
bool replace_(const value_type& v,node_type* x,rvalue_tag)
{
x->value()=boost::move(const_cast<value_type&>(v));
return true;
}
bool modify_(node_type*){return true;}
bool modify_rollback_(node_type*){return true;}
#if !defined(BOOST_MULTI_INDEX_DISABLE_SERIALIZATION)
/* serialization */
template<typename Archive>
void save_(Archive&,const unsigned int,const index_saver_type&)const{}
template<typename Archive>
void load_(Archive&,const unsigned int,const index_loader_type&){}
#endif
#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<final_type*>(this);}
const final_type& final()const{return *static_cast<const final_type*>(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_node_type*,bool> final_insert_(const value_type& x)
{return final().insert_(x);}
std::pair<final_node_type*,bool> final_insert_rv_(const value_type& x)
{return final().insert_rv_(x);}
template<typename T>
std::pair<final_node_type*,bool> final_insert_ref_(const T& t)
{return final().insert_ref_(t);}
template<typename T>
std::pair<final_node_type*,bool> final_insert_ref_(T& t)
{return final().insert_ref_(t);}
template<BOOST_MULTI_INDEX_TEMPLATE_PARAM_PACK>
std::pair<final_node_type*,bool> final_emplace_(
BOOST_MULTI_INDEX_FUNCTION_PARAM_PACK)
{
return final().emplace_(BOOST_MULTI_INDEX_FORWARD_PARAM_PACK);
}
std::pair<final_node_type*,bool> final_insert_(
const value_type& x,final_node_type* position)
{return final().insert_(x,position);}
std::pair<final_node_type*,bool> final_insert_rv_(
const value_type& x,final_node_type* position)
{return final().insert_rv_(x,position);}
template<typename T>
std::pair<final_node_type*,bool> final_insert_ref_(
const T& t,final_node_type* position)
{return final().insert_ref_(t,position);}
template<typename T>
std::pair<final_node_type*,bool> final_insert_ref_(
T& t,final_node_type* position)
{return final().insert_ref_(t,position);}
template<BOOST_MULTI_INDEX_TEMPLATE_PARAM_PACK>
std::pair<final_node_type*,bool> final_emplace_hint_(
final_node_type* position,BOOST_MULTI_INDEX_FUNCTION_PARAM_PACK)
{
return final().emplace_hint_(
position,BOOST_MULTI_INDEX_FORWARD_PARAM_PACK);
}
void final_erase_(final_node_type* x){final().erase_(x);}
void final_delete_node_(final_node_type* x){final().delete_node_(x);}
void final_delete_all_nodes_(){final().delete_all_nodes_();}
void final_clear_(){final().clear_();}
void final_swap_(final_type& x){final().swap_(x);}
bool final_replace_(
const value_type& k,final_node_type* x)
{return final().replace_(k,x);}
bool final_replace_rv_(
const value_type& k,final_node_type* x)
{return final().replace_rv_(k,x);}
template<typename Modifier>
bool final_modify_(Modifier& mod,final_node_type* x)
{return final().modify_(mod,x);}
template<typename Modifier,typename Rollback>
bool final_modify_(Modifier& mod,Rollback& back,final_node_type* x)
{return final().modify_(mod,back,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
@@ -0,0 +1,139 @@
/* Copyright 2003-2015 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_INDEX_LOADER_HPP
#define BOOST_MULTI_INDEX_DETAIL_INDEX_LOADER_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <algorithm>
#include <boost/archive/archive_exception.hpp>
#include <boost/noncopyable.hpp>
#include <boost/multi_index/detail/auto_space.hpp>
#include <boost/multi_index/detail/raw_ptr.hpp>
#include <boost/serialization/nvp.hpp>
#include <boost/throw_exception.hpp>
#include <cstddef>
namespace boost{
namespace multi_index{
namespace detail{
/* Counterpart of index_saver (check index_saver.hpp for serialization
* details.)* multi_index_container is in charge of supplying the info about
* the base sequence, and each index can subsequently load itself using the
* const interface of index_loader.
*/
template<typename Node,typename FinalNode,typename Allocator>
class index_loader:private noncopyable
{
public:
index_loader(const Allocator& al,std::size_t size):
spc(al,size),size_(size),n(0),sorted(false)
{
}
template<class Archive>
void add(Node* node,Archive& ar,const unsigned int)
{
ar>>serialization::make_nvp("position",*node);
entries()[n++]=node;
}
template<class Archive>
void add_track(Node* node,Archive& ar,const unsigned int)
{
ar>>serialization::make_nvp("position",*node);
}
/* A rearranger is passed two nodes, and is expected to
* reposition the second after the first.
* If the first node is 0, then the second should be moved
* to the beginning of the sequence.
*/
template<typename Rearranger,class Archive>
void load(Rearranger r,Archive& ar,const unsigned int)const
{
FinalNode* prev=unchecked_load_node(ar);
if(!prev)return;
if(!sorted){
std::sort(entries(),entries()+size_);
sorted=true;
}
check_node(prev);
for(;;){
for(;;){
FinalNode* node=load_node(ar);
if(!node)break;
if(node==prev)prev=0;
r(prev,node);
prev=node;
}
prev=load_node(ar);
if(!prev)break;
}
}
private:
Node** entries()const{return raw_ptr<Node**>(spc.data());}
/* We try to delay sorting as much as possible just in case it
* is not necessary, hence this version of load_node.
*/
template<class Archive>
FinalNode* unchecked_load_node(Archive& ar)const
{
Node* node=0;
ar>>serialization::make_nvp("pointer",node);
return static_cast<FinalNode*>(node);
}
template<class Archive>
FinalNode* load_node(Archive& ar)const
{
Node* node=0;
ar>>serialization::make_nvp("pointer",node);
check_node(node);
return static_cast<FinalNode*>(node);
}
void check_node(Node* node)const
{
if(node!=0&&!std::binary_search(entries(),entries()+size_,node)){
throw_exception(
archive::archive_exception(
archive::archive_exception::other_exception));
}
}
auto_space<Node*,Allocator> spc;
std::size_t size_;
std::size_t n;
mutable bool sorted;
};
} /* namespace multi_index::detail */
} /* namespace multi_index */
} /* namespace boost */
#endif
@@ -0,0 +1,249 @@
/* Copyright 2003-2015 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_INDEX_MATCHER_HPP
#define BOOST_MULTI_INDEX_DETAIL_INDEX_MATCHER_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <algorithm>
#include <boost/noncopyable.hpp>
#include <boost/multi_index/detail/auto_space.hpp>
#include <boost/multi_index/detail/raw_ptr.hpp>
#include <cstddef>
#include <functional>
namespace boost{
namespace multi_index{
namespace detail{
/* index_matcher compares a sequence of elements against a
* base sequence, identifying those elements that belong to the
* longest subsequence which is ordered with respect to the base.
* For instance, if the base sequence is:
*
* 0 1 2 3 4 5 6 7 8 9
*
* and the compared sequence (not necesarilly the same length):
*
* 1 4 2 3 0 7 8 9
*
* the elements of the longest ordered subsequence are:
*
* 1 2 3 7 8 9
*
* The algorithm for obtaining such a subsequence is called
* Patience Sorting, described in ch. 1 of:
* Aldous, D., Diaconis, P.: "Longest increasing subsequences: from
* patience sorting to the Baik-Deift-Johansson Theorem", Bulletin
* of the American Mathematical Society, vol. 36, no 4, pp. 413-432,
* July 1999.
* http://www.ams.org/bull/1999-36-04/S0273-0979-99-00796-X/
* S0273-0979-99-00796-X.pdf
*
* This implementation is not fully generic since it assumes that
* the sequences given are pointed to by index iterators (having a
* get_node() memfun.)
*/
namespace index_matcher{
/* The algorithm stores the nodes of the base sequence and a number
* of "piles" that are dynamically updated during the calculation
* stage. From a logical point of view, nodes form an independent
* sequence from piles. They are stored together so as to minimize
* allocated memory.
*/
struct entry
{
entry(void* node_,std::size_t pos_=0):node(node_),pos(pos_){}
/* node stuff */
void* node;
std::size_t pos;
entry* previous;
bool ordered;
struct less_by_node
{
bool operator()(
const entry& x,const entry& y)const
{
return std::less<void*>()(x.node,y.node);
}
};
/* pile stuff */
std::size_t pile_top;
entry* pile_top_entry;
struct less_by_pile_top
{
bool operator()(
const entry& x,const entry& y)const
{
return x.pile_top<y.pile_top;
}
};
};
/* common code operating on void *'s */
template<typename Allocator>
class algorithm_base:private noncopyable
{
protected:
algorithm_base(const Allocator& al,std::size_t size):
spc(al,size),size_(size),n_(0),sorted(false)
{
}
void add(void* node)
{
entries()[n_]=entry(node,n_);
++n_;
}
void begin_algorithm()const
{
if(!sorted){
std::sort(entries(),entries()+size_,entry::less_by_node());
sorted=true;
}
num_piles=0;
}
void add_node_to_algorithm(void* node)const
{
entry* ent=
std::lower_bound(
entries(),entries()+size_,
entry(node),entry::less_by_node()); /* localize entry */
ent->ordered=false;
std::size_t n=ent->pos; /* get its position */
entry dummy(0);
dummy.pile_top=n;
entry* pile_ent= /* find the first available pile */
std::lower_bound( /* to stack the entry */
entries(),entries()+num_piles,
dummy,entry::less_by_pile_top());
pile_ent->pile_top=n; /* stack the entry */
pile_ent->pile_top_entry=ent;
/* if not the first pile, link entry to top of the preceding pile */
if(pile_ent>&entries()[0]){
ent->previous=(pile_ent-1)->pile_top_entry;
}
if(pile_ent==&entries()[num_piles]){ /* new pile? */
++num_piles;
}
}
void finish_algorithm()const
{
if(num_piles>0){
/* Mark those elements which are in their correct position, i.e. those
* belonging to the longest increasing subsequence. These are those
* elements linked from the top of the last pile.
*/
entry* ent=entries()[num_piles-1].pile_top_entry;
for(std::size_t n=num_piles;n--;){
ent->ordered=true;
ent=ent->previous;
}
}
}
bool is_ordered(void * node)const
{
return std::lower_bound(
entries(),entries()+size_,
entry(node),entry::less_by_node())->ordered;
}
private:
entry* entries()const{return raw_ptr<entry*>(spc.data());}
auto_space<entry,Allocator> spc;
std::size_t size_;
std::size_t n_;
mutable bool sorted;
mutable std::size_t num_piles;
};
/* The algorithm has three phases:
* - Initialization, during which the nodes of the base sequence are added.
* - Execution.
* - Results querying, through the is_ordered memfun.
*/
template<typename Node,typename Allocator>
class algorithm:private algorithm_base<Allocator>
{
typedef algorithm_base<Allocator> super;
public:
algorithm(const Allocator& al,std::size_t size):super(al,size){}
void add(Node* node)
{
super::add(node);
}
template<typename IndexIterator>
void execute(IndexIterator first,IndexIterator last)const
{
super::begin_algorithm();
for(IndexIterator it=first;it!=last;++it){
add_node_to_algorithm(get_node(it));
}
super::finish_algorithm();
}
bool is_ordered(Node* node)const
{
return super::is_ordered(node);
}
private:
void add_node_to_algorithm(Node* node)const
{
super::add_node_to_algorithm(node);
}
template<typename IndexIterator>
static Node* get_node(IndexIterator it)
{
return static_cast<Node*>(it.get_node());
}
};
} /* namespace multi_index::detail::index_matcher */
} /* namespace multi_index::detail */
} /* namespace multi_index */
} /* namespace boost */
#endif
@@ -0,0 +1,135 @@
/* Copyright 2003-2016 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_INDEX_NODE_BASE_HPP
#define BOOST_MULTI_INDEX_DETAIL_INDEX_NODE_BASE_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <boost/type_traits/aligned_storage.hpp>
#include <boost/type_traits/alignment_of.hpp>
#if !defined(BOOST_MULTI_INDEX_DISABLE_SERIALIZATION)
#include <boost/archive/archive_exception.hpp>
#include <boost/serialization/access.hpp>
#include <boost/throw_exception.hpp>
#endif
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<typename Value>
struct pod_value_holder
{
typename aligned_storage<
sizeof(Value),
alignment_of<Value>::value
>::type space;
};
template<typename Value,typename Allocator>
struct index_node_base:private pod_value_holder<Value>
{
typedef index_node_base base_type; /* used for serialization purposes */
typedef Value value_type;
typedef Allocator allocator_type;
#include <boost/multi_index/detail/ignore_wstrict_aliasing.hpp>
value_type& value()
{
return *reinterpret_cast<value_type*>(&this->space);
}
const value_type& value()const
{
return *reinterpret_cast<const value_type*>(&this->space);
}
#include <boost/multi_index/detail/restore_wstrict_aliasing.hpp>
static index_node_base* from_value(const value_type* p)
{
return static_cast<index_node_base *>(
reinterpret_cast<pod_value_holder<Value>*>( /* std 9.2.17 */
const_cast<value_type*>(p)));
}
private:
#if !defined(BOOST_MULTI_INDEX_DISABLE_SERIALIZATION)
friend class boost::serialization::access;
/* nodes do not emit any kind of serialization info. They are
* fed to Boost.Serialization so that pointers to nodes are
* tracked correctly.
*/
template<class Archive>
void serialize(Archive&,const unsigned int)
{
}
#endif
};
template<typename Node,typename Value>
Node* node_from_value(const Value* p)
{
typedef typename Node::allocator_type allocator_type;
return static_cast<Node*>(
index_node_base<Value,allocator_type>::from_value(p));
}
} /* namespace multi_index::detail */
} /* namespace multi_index */
#if !defined(BOOST_MULTI_INDEX_DISABLE_SERIALIZATION)
/* Index nodes never get constructed directly by Boost.Serialization,
* as archives are always fed pointers to previously existent
* nodes. So, if this is called it means we are dealing with a
* somehow invalid archive.
*/
#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
namespace serialization{
#else
namespace multi_index{
namespace detail{
#endif
template<class Archive,typename Value,typename Allocator>
inline void load_construct_data(
Archive&,boost::multi_index::detail::index_node_base<Value,Allocator>*,
const unsigned int)
{
throw_exception(
archive::archive_exception(archive::archive_exception::other_exception));
}
#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
} /* namespace serialization */
#else
} /* namespace multi_index::detail */
} /* namespace multi_index */
#endif
#endif
} /* namespace boost */
#endif
@@ -0,0 +1,135 @@
/* Copyright 2003-2013 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_INDEX_SAVER_HPP
#define BOOST_MULTI_INDEX_DETAIL_INDEX_SAVER_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <boost/multi_index/detail/index_matcher.hpp>
#include <boost/noncopyable.hpp>
#include <boost/serialization/nvp.hpp>
#include <cstddef>
namespace boost{
namespace multi_index{
namespace detail{
/* index_saver accepts a base sequence of previously saved elements
* and saves a possibly reordered subsequence in an efficient manner,
* serializing only the information needed to rearrange the subsequence
* based on the original order of the base.
* multi_index_container is in charge of supplying the info about the
* base sequence, and each index can subsequently save itself using the
* const interface of index_saver.
*/
template<typename Node,typename Allocator>
class index_saver:private noncopyable
{
public:
index_saver(const Allocator& al,std::size_t size):alg(al,size){}
template<class Archive>
void add(Node* node,Archive& ar,const unsigned int)
{
ar<<serialization::make_nvp("position",*node);
alg.add(node);
}
template<class Archive>
void add_track(Node* node,Archive& ar,const unsigned int)
{
ar<<serialization::make_nvp("position",*node);
}
template<typename IndexIterator,class Archive>
void save(
IndexIterator first,IndexIterator last,Archive& ar,
const unsigned int)const
{
/* calculate ordered positions */
alg.execute(first,last);
/* Given a consecutive subsequence of displaced elements
* x1,...,xn, the following information is serialized:
*
* p0,p1,...,pn,0
*
* where pi is a pointer to xi and p0 is a pointer to the element
* preceding x1. Crealy, from this information is possible to
* restore the original order on loading time. If x1 is the first
* element in the sequence, the following is serialized instead:
*
* p1,p1,...,pn,0
*
* For each subsequence of n elements, n+2 pointers are serialized.
* An optimization policy is applied: consider for instance the
* sequence
*
* a,B,c,D
*
* where B and D are displaced, but c is in its correct position.
* Applying the schema described above we would serialize 6 pointers:
*
* p(a),p(B),0
* p(c),p(D),0
*
* but this can be reduced to 5 pointers by treating c as a displaced
* element:
*
* p(a),p(B),p(c),p(D),0
*/
std::size_t last_saved=3; /* distance to last pointer saved */
for(IndexIterator it=first,prev=first;it!=last;prev=it++,++last_saved){
if(!alg.is_ordered(get_node(it))){
if(last_saved>1)save_node(get_node(prev),ar);
save_node(get_node(it),ar);
last_saved=0;
}
else if(last_saved==2)save_node(null_node(),ar);
}
if(last_saved<=2)save_node(null_node(),ar);
/* marks the end of the serialization info for [first,last) */
save_node(null_node(),ar);
}
private:
template<typename IndexIterator>
static Node* get_node(IndexIterator it)
{
return it.get_node();
}
static Node* null_node(){return 0;}
template<typename Archive>
static void save_node(Node* node,Archive& ar)
{
ar<<serialization::make_nvp("pointer",node);
}
index_matcher::algorithm<Node,Allocator> alg;
};
} /* namespace multi_index::detail */
} /* namespace multi_index */
} /* namespace boost */
#endif
@@ -0,0 +1,21 @@
/* Copyright 2003-2013 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_INVARIANT_ASSERT_HPP
#define BOOST_MULTI_INDEX_DETAIL_INVARIANT_ASSERT_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#if !defined(BOOST_MULTI_INDEX_INVARIANT_ASSERT)
#include <boost/assert.hpp>
#define BOOST_MULTI_INDEX_INVARIANT_ASSERT BOOST_ASSERT
#endif
#endif
@@ -0,0 +1,40 @@
/* Copyright 2003-2013 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_IS_INDEX_LIST_HPP
#define BOOST_MULTI_INDEX_DETAIL_IS_INDEX_LIST_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <boost/mpl/empty.hpp>
#include <boost/mpl/is_sequence.hpp>
namespace boost{
namespace multi_index{
namespace detail{
template<typename T>
struct is_index_list
{
BOOST_STATIC_CONSTANT(bool,mpl_sequence=mpl::is_sequence<T>::value);
BOOST_STATIC_CONSTANT(bool,non_empty=!mpl::empty<T>::value);
BOOST_STATIC_CONSTANT(bool,value=mpl_sequence&&non_empty);
};
} /* namespace multi_index::detail */
} /* namespace multi_index */
} /* namespace boost */
#endif
@@ -0,0 +1,135 @@
/* Copyright 2003-2014 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_IS_TRANSPARENT_HPP
#define BOOST_MULTI_INDEX_DETAIL_IS_TRANSPARENT_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <boost/mpl/bool.hpp>
#include <boost/type_traits/intrinsics.hpp>
namespace boost{
namespace multi_index{
namespace detail{
/* Metafunction that checks if f(arg,arg2) executes without argument type
* conversion. By default (i.e. when it cannot be determined) it evaluates to
* true.
*/
template<typename F,typename Arg1,typename Arg2,typename=void>
struct is_transparent:mpl::true_{};
} /* namespace multi_index::detail */
} /* namespace multi_index */
} /* namespace boost */
#if !defined(BOOST_NO_SFINAE)&&!defined(BOOST_NO_SFINAE_EXPR)&& \
!defined(BOOST_NO_CXX11_DECLTYPE)&& \
(defined(BOOST_NO_CXX11_FINAL)||defined(BOOST_IS_FINAL))
#include <boost/mpl/and.hpp>
#include <boost/mpl/not.hpp>
#include <boost/mpl/or.hpp>
#include <boost/type_traits/function_traits.hpp>
#include <boost/type_traits/is_class.hpp>
#include <boost/type_traits/is_final.hpp>
#include <boost/type_traits/is_function.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/type_traits/remove_pointer.hpp>
#include <boost/utility/declval.hpp>
#include <boost/utility/enable_if.hpp>
namespace boost{
namespace multi_index{
namespace detail{
struct not_is_transparent_result_type{};
template<typename F,typename Arg1,typename Arg2>
struct is_transparent_class_helper:F
{
using F::operator();
template<typename T,typename Q>
not_is_transparent_result_type operator()(const T&,const Q&)const;
};
template<typename F,typename Arg1,typename Arg2,typename=void>
struct is_transparent_class:mpl::true_{};
template<typename F,typename Arg1,typename Arg2>
struct is_transparent_class<
F,Arg1,Arg2,
typename enable_if<
is_same<
decltype(
declval<const is_transparent_class_helper<F,Arg1,Arg2> >()(
declval<const Arg1&>(),declval<const Arg2&>())
),
not_is_transparent_result_type
>
>::type
>:mpl::false_{};
template<typename F,typename Arg1,typename Arg2>
struct is_transparent<
F,Arg1,Arg2,
typename enable_if<
mpl::and_<
is_class<F>,
mpl::not_<is_final<F> > /* is_transparent_class_helper derives from F */
>
>::type
>:is_transparent_class<F,Arg1,Arg2>{};
template<typename F,typename Arg1,typename Arg2,typename=void>
struct is_transparent_function:mpl::true_{};
template<typename F,typename Arg1,typename Arg2>
struct is_transparent_function<
F,Arg1,Arg2,
typename enable_if<
mpl::or_<
mpl::not_<mpl::or_<
is_same<typename function_traits<F>::arg1_type,const Arg1&>,
is_same<typename function_traits<F>::arg1_type,Arg1>
> >,
mpl::not_<mpl::or_<
is_same<typename function_traits<F>::arg2_type,const Arg2&>,
is_same<typename function_traits<F>::arg2_type,Arg2>
> >
>
>::type
>:mpl::false_{};
template<typename F,typename Arg1,typename Arg2>
struct is_transparent<
F,Arg1,Arg2,
typename enable_if<
is_function<typename remove_pointer<F>::type>
>::type
>:is_transparent_function<typename remove_pointer<F>::type,Arg1,Arg2>{};
} /* namespace multi_index::detail */
} /* namespace multi_index */
} /* namespace boost */
#endif
#endif
@@ -0,0 +1,321 @@
/* Copyright 2003-2013 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_ITER_ADAPTOR_HPP
#define BOOST_MULTI_INDEX_DETAIL_ITER_ADAPTOR_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <boost/mpl/apply.hpp>
#include <boost/operators.hpp>
namespace boost{
namespace multi_index{
namespace detail{
/* Poor man's version of boost::iterator_adaptor. Used instead of the
* original as compile times for the latter are significantly higher.
* The interface is not replicated exactly, only to the extent necessary
* for internal consumption.
*/
/* NB. The purpose of the (non-inclass) global operators ==, < and - defined
* above is to partially alleviate a problem of MSVC++ 6.0 by * which
* friend-injected operators on T are not visible if T is instantiated only
* in template code where T is a dependent type.
*/
class iter_adaptor_access
{
public:
template<class Class>
static typename Class::reference dereference(const Class& x)
{
return x.dereference();
}
template<class Class>
static bool equal(const Class& x,const Class& y)
{
return x.equal(y);
}
template<class Class>
static void increment(Class& x)
{
x.increment();
}
template<class Class>
static void decrement(Class& x)
{
x.decrement();
}
template<class Class>
static void advance(Class& x,typename Class::difference_type n)
{
x.advance(n);
}
template<class Class>
static typename Class::difference_type distance_to(
const Class& x,const Class& y)
{
return x.distance_to(y);
}
};
template<typename Category>
struct iter_adaptor_selector;
template<class Derived,class Base>
class forward_iter_adaptor_base:
public forward_iterator_helper<
Derived,
typename Base::value_type,
typename Base::difference_type,
typename Base::pointer,
typename Base::reference>
{
public:
typedef typename Base::reference reference;
reference operator*()const
{
return iter_adaptor_access::dereference(final());
}
friend bool operator==(const Derived& x,const Derived& y)
{
return iter_adaptor_access::equal(x,y);
}
Derived& operator++()
{
iter_adaptor_access::increment(final());
return final();
}
private:
Derived& final(){return *static_cast<Derived*>(this);}
const Derived& final()const{return *static_cast<const Derived*>(this);}
};
template<class Derived,class Base>
bool operator==(
const forward_iter_adaptor_base<Derived,Base>& x,
const forward_iter_adaptor_base<Derived,Base>& y)
{
return iter_adaptor_access::equal(
static_cast<const Derived&>(x),static_cast<const Derived&>(y));
}
template<>
struct iter_adaptor_selector<std::forward_iterator_tag>
{
template<class Derived,class Base>
struct apply
{
typedef forward_iter_adaptor_base<Derived,Base> type;
};
};
template<class Derived,class Base>
class bidirectional_iter_adaptor_base:
public bidirectional_iterator_helper<
Derived,
typename Base::value_type,
typename Base::difference_type,
typename Base::pointer,
typename Base::reference>
{
public:
typedef typename Base::reference reference;
reference operator*()const
{
return iter_adaptor_access::dereference(final());
}
friend bool operator==(const Derived& x,const Derived& y)
{
return iter_adaptor_access::equal(x,y);
}
Derived& operator++()
{
iter_adaptor_access::increment(final());
return final();
}
Derived& operator--()
{
iter_adaptor_access::decrement(final());
return final();
}
private:
Derived& final(){return *static_cast<Derived*>(this);}
const Derived& final()const{return *static_cast<const Derived*>(this);}
};
template<class Derived,class Base>
bool operator==(
const bidirectional_iter_adaptor_base<Derived,Base>& x,
const bidirectional_iter_adaptor_base<Derived,Base>& y)
{
return iter_adaptor_access::equal(
static_cast<const Derived&>(x),static_cast<const Derived&>(y));
}
template<>
struct iter_adaptor_selector<std::bidirectional_iterator_tag>
{
template<class Derived,class Base>
struct apply
{
typedef bidirectional_iter_adaptor_base<Derived,Base> type;
};
};
template<class Derived,class Base>
class random_access_iter_adaptor_base:
public random_access_iterator_helper<
Derived,
typename Base::value_type,
typename Base::difference_type,
typename Base::pointer,
typename Base::reference>
{
public:
typedef typename Base::reference reference;
typedef typename Base::difference_type difference_type;
reference operator*()const
{
return iter_adaptor_access::dereference(final());
}
friend bool operator==(const Derived& x,const Derived& y)
{
return iter_adaptor_access::equal(x,y);
}
friend bool operator<(const Derived& x,const Derived& y)
{
return iter_adaptor_access::distance_to(x,y)>0;
}
Derived& operator++()
{
iter_adaptor_access::increment(final());
return final();
}
Derived& operator--()
{
iter_adaptor_access::decrement(final());
return final();
}
Derived& operator+=(difference_type n)
{
iter_adaptor_access::advance(final(),n);
return final();
}
Derived& operator-=(difference_type n)
{
iter_adaptor_access::advance(final(),-n);
return final();
}
friend difference_type operator-(const Derived& x,const Derived& y)
{
return iter_adaptor_access::distance_to(y,x);
}
private:
Derived& final(){return *static_cast<Derived*>(this);}
const Derived& final()const{return *static_cast<const Derived*>(this);}
};
template<class Derived,class Base>
bool operator==(
const random_access_iter_adaptor_base<Derived,Base>& x,
const random_access_iter_adaptor_base<Derived,Base>& y)
{
return iter_adaptor_access::equal(
static_cast<const Derived&>(x),static_cast<const Derived&>(y));
}
template<class Derived,class Base>
bool operator<(
const random_access_iter_adaptor_base<Derived,Base>& x,
const random_access_iter_adaptor_base<Derived,Base>& y)
{
return iter_adaptor_access::distance_to(
static_cast<const Derived&>(x),static_cast<const Derived&>(y))>0;
}
template<class Derived,class Base>
typename random_access_iter_adaptor_base<Derived,Base>::difference_type
operator-(
const random_access_iter_adaptor_base<Derived,Base>& x,
const random_access_iter_adaptor_base<Derived,Base>& y)
{
return iter_adaptor_access::distance_to(
static_cast<const Derived&>(y),static_cast<const Derived&>(x));
}
template<>
struct iter_adaptor_selector<std::random_access_iterator_tag>
{
template<class Derived,class Base>
struct apply
{
typedef random_access_iter_adaptor_base<Derived,Base> type;
};
};
template<class Derived,class Base>
struct iter_adaptor_base
{
typedef iter_adaptor_selector<
typename Base::iterator_category> selector;
typedef typename mpl::apply2<
selector,Derived,Base>::type type;
};
template<class Derived,class Base>
class iter_adaptor:public iter_adaptor_base<Derived,Base>::type
{
protected:
iter_adaptor(){}
explicit iter_adaptor(const Base& b_):b(b_){}
const Base& base_reference()const{return b;}
Base& base_reference(){return b;}
private:
Base b;
};
} /* namespace multi_index::detail */
} /* namespace multi_index */
} /* namespace boost */
#endif
@@ -0,0 +1,49 @@
/* Copyright 2003-2013 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_MODIFY_KEY_ADAPTOR_HPP
#define BOOST_MULTI_INDEX_DETAIL_MODIFY_KEY_ADAPTOR_HPP
#if defined(_MSC_VER)
#pragma once
#endif
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<typename Fun,typename Value,typename KeyFromValue>
struct modify_key_adaptor
{
modify_key_adaptor(Fun f_,KeyFromValue kfv_):f(f_),kfv(kfv_){}
void operator()(Value& x)
{
f(kfv(x));
}
private:
Fun f;
KeyFromValue kfv;
};
} /* namespace multi_index::detail */
} /* namespace multi_index */
} /* namespace boost */
#endif
@@ -0,0 +1,97 @@
/* Copyright 2003-2013 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_NO_DUPLICATE_TAGS_HPP
#define BOOST_MULTI_INDEX_DETAIL_NO_DUPLICATE_TAGS_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <boost/mpl/fold.hpp>
#include <boost/mpl/set/set0.hpp>
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 <typename MplSet,typename Tag>
struct apply
{
typedef mpl::s_item<
typename mpl::if_<mpl::has_key<MplSet,Tag>,duplicate_tag_mark,Tag>::type,
MplSet
> type;
};
};
template<typename TagList>
struct no_duplicate_tags
{
typedef typename mpl::fold<
TagList,
mpl::set0<>,
duplicate_tag_marker
>::type aux;
BOOST_STATIC_CONSTANT(
bool,value=!(mpl::has_key<aux,duplicate_tag_mark>::value));
};
/* Variant for an index list: duplication is checked
* across all the indices.
*/
struct duplicate_tag_list_marker
{
template <typename MplSet,typename Index>
struct apply:mpl::fold<
BOOST_DEDUCED_TYPENAME Index::tag_list,
MplSet,
duplicate_tag_marker>
{
};
};
template<typename IndexList>
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<aux,duplicate_tag_mark>::value));
};
} /* namespace multi_index::detail */
} /* namespace multi_index */
} /* namespace boost */
#endif
@@ -0,0 +1,66 @@
/* Copyright 2003-2013 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_NODE_TYPE_HPP
#define BOOST_MULTI_INDEX_DETAIL_NODE_TYPE_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <boost/detail/workaround.hpp>
#include <boost/mpl/bind.hpp>
#include <boost/mpl/reverse_iter_fold.hpp>
#include <boost/mpl/deref.hpp>
#include <boost/multi_index_container_fwd.hpp>
#include <boost/multi_index/detail/header_holder.hpp>
#include <boost/multi_index/detail/index_node_base.hpp>
#include <boost/multi_index/detail/is_index_list.hpp>
#include <boost/static_assert.hpp>
namespace boost{
namespace multi_index{
namespace detail{
/* MPL machinery to construct the internal node type associated to an
* index list.
*/
struct index_node_applier
{
template<typename IndexSpecifierIterator,typename Super>
struct apply
{
typedef typename mpl::deref<IndexSpecifierIterator>::type index_specifier;
typedef typename index_specifier::
BOOST_NESTED_TEMPLATE node_class<Super>::type type;
};
};
template<typename Value,typename IndexSpecifierList,typename Allocator>
struct multi_index_node_type
{
BOOST_STATIC_ASSERT(detail::is_index_list<IndexSpecifierList>::value);
typedef typename mpl::reverse_iter_fold<
IndexSpecifierList,
index_node_base<Value,Allocator>,
mpl::bind2<index_node_applier,mpl::_2,mpl::_1>
>::type type;
};
} /* namespace multi_index::detail */
} /* namespace multi_index */
} /* namespace boost */
#endif
@@ -0,0 +1,83 @@
/* Copyright 2003-2013 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_ORD_INDEX_ARGS_HPP
#define BOOST_MULTI_INDEX_DETAIL_ORD_INDEX_ARGS_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <boost/mpl/aux_/na.hpp>
#include <boost/mpl/eval_if.hpp>
#include <boost/mpl/identity.hpp>
#include <boost/mpl/if.hpp>
#include <boost/multi_index/tag.hpp>
#include <boost/static_assert.hpp>
#include <boost/type_traits/is_same.hpp>
#include <functional>
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<KeyFromValue::result_type> >
* (ordered_unique|ordered_non_unique)<
* TagList,KeyFromValue,Compare=std::less<KeyFromValue::result_type> >
*
* index_args implements the machinery to accept this argument-dependent
* polymorphism.
*/
template<typename KeyFromValue>
struct index_args_default_compare
{
typedef std::less<typename KeyFromValue::result_type> type;
};
template<typename Arg1,typename Arg2,typename Arg3>
struct ordered_index_args
{
typedef is_tag<Arg1> 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::eval_if<
mpl::is_na<supplied_compare_type>,
index_args_default_compare<key_from_value_type>,
mpl::identity<supplied_compare_type>
>::type compare_type;
BOOST_STATIC_ASSERT(is_tag<tag_list_type>::value);
BOOST_STATIC_ASSERT(!mpl::is_na<key_from_value_type>::value);
BOOST_STATIC_ASSERT(!mpl::is_na<compare_type>::value);
};
} /* namespace multi_index::detail */
} /* namespace multi_index */
} /* namespace boost */
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,128 @@
/* Copyright 2003-2015 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_ORD_INDEX_IMPL_FWD_HPP
#define BOOST_MULTI_INDEX_DETAIL_ORD_INDEX_IMPL_FWD_HPP
#if defined(_MSC_VER)
#pragma once
#endif
namespace boost{
namespace multi_index{
namespace detail{
template<
typename KeyFromValue,typename Compare,
typename SuperMeta,typename TagList,typename Category,typename AugmentPolicy
>
class ordered_index;
template<
typename KeyFromValue1,typename Compare1,
typename SuperMeta1,typename TagList1,typename Category1,
typename AugmentPolicy1,
typename KeyFromValue2,typename Compare2,
typename SuperMeta2,typename TagList2,typename Category2,
typename AugmentPolicy2
>
bool operator==(
const ordered_index<
KeyFromValue1,Compare1,SuperMeta1,TagList1,Category1,AugmentPolicy1>& x,
const ordered_index<
KeyFromValue2,Compare2,SuperMeta2,TagList2,Category2,AugmentPolicy2>& y);
template<
typename KeyFromValue1,typename Compare1,
typename SuperMeta1,typename TagList1,typename Category1,
typename AugmentPolicy1,
typename KeyFromValue2,typename Compare2,
typename SuperMeta2,typename TagList2,typename Category2,
typename AugmentPolicy2
>
bool operator<(
const ordered_index<
KeyFromValue1,Compare1,SuperMeta1,TagList1,Category1,AugmentPolicy1>& x,
const ordered_index<
KeyFromValue2,Compare2,SuperMeta2,TagList2,Category2,AugmentPolicy2>& y);
template<
typename KeyFromValue1,typename Compare1,
typename SuperMeta1,typename TagList1,typename Category1,
typename AugmentPolicy1,
typename KeyFromValue2,typename Compare2,
typename SuperMeta2,typename TagList2,typename Category2,
typename AugmentPolicy2
>
bool operator!=(
const ordered_index<
KeyFromValue1,Compare1,SuperMeta1,TagList1,Category1,AugmentPolicy1>& x,
const ordered_index<
KeyFromValue2,Compare2,SuperMeta2,TagList2,Category2,AugmentPolicy2>& y);
template<
typename KeyFromValue1,typename Compare1,
typename SuperMeta1,typename TagList1,typename Category1,
typename AugmentPolicy1,
typename KeyFromValue2,typename Compare2,
typename SuperMeta2,typename TagList2,typename Category2,
typename AugmentPolicy2
>
bool operator>(
const ordered_index<
KeyFromValue1,Compare1,SuperMeta1,TagList1,Category1,AugmentPolicy1>& x,
const ordered_index<
KeyFromValue2,Compare2,SuperMeta2,TagList2,Category2,AugmentPolicy2>& y);
template<
typename KeyFromValue1,typename Compare1,
typename SuperMeta1,typename TagList1,typename Category1,
typename AugmentPolicy1,
typename KeyFromValue2,typename Compare2,
typename SuperMeta2,typename TagList2,typename Category2,
typename AugmentPolicy2
>
bool operator>=(
const ordered_index<
KeyFromValue1,Compare1,SuperMeta1,TagList1,Category1,AugmentPolicy1>& x,
const ordered_index<
KeyFromValue2,Compare2,SuperMeta2,TagList2,Category2,AugmentPolicy2>& y);
template<
typename KeyFromValue1,typename Compare1,
typename SuperMeta1,typename TagList1,typename Category1,
typename AugmentPolicy1,
typename KeyFromValue2,typename Compare2,
typename SuperMeta2,typename TagList2,typename Category2,
typename AugmentPolicy2
>
bool operator<=(
const ordered_index<
KeyFromValue1,Compare1,SuperMeta1,TagList1,Category1,AugmentPolicy1>& x,
const ordered_index<
KeyFromValue2,Compare2,SuperMeta2,TagList2,Category2,AugmentPolicy2>& y);
template<
typename KeyFromValue,typename Compare,
typename SuperMeta,typename TagList,typename Category,typename AugmentPolicy
>
void swap(
ordered_index<
KeyFromValue,Compare,SuperMeta,TagList,Category,AugmentPolicy>& x,
ordered_index<
KeyFromValue,Compare,SuperMeta,TagList,Category,AugmentPolicy>& y);
} /* namespace multi_index::detail */
} /* namespace multi_index */
} /* namespace boost */
#endif
@@ -0,0 +1,658 @@
/* Copyright 2003-2015 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*
* 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
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <cstddef>
#include <boost/detail/allocator_utilities.hpp>
#include <boost/multi_index/detail/raw_ptr.hpp>
#if !defined(BOOST_MULTI_INDEX_DISABLE_COMPRESSED_ORDERED_INDEX_NODES)
#include <boost/mpl/and.hpp>
#include <boost/mpl/if.hpp>
#include <boost/multi_index/detail/uintptr_type.hpp>
#include <boost/type_traits/alignment_of.hpp>
#include <boost/type_traits/is_same.hpp>
#endif
namespace boost{
namespace multi_index{
namespace detail{
/* definition of red-black nodes for ordered_index */
enum ordered_index_color{red=false,black=true};
enum ordered_index_side{to_left=false,to_right=true};
template<typename AugmentPolicy,typename Allocator>
struct ordered_index_node_impl; /* fwd decl. */
template<typename AugmentPolicy,typename Allocator>
struct ordered_index_node_std_base
{
typedef typename
boost::detail::allocator::rebind_to<
Allocator,
ordered_index_node_impl<AugmentPolicy,Allocator>
>::type::pointer pointer;
typedef typename
boost::detail::allocator::rebind_to<
Allocator,
ordered_index_node_impl<AugmentPolicy,Allocator>
>::type::const_pointer const_pointer;
typedef ordered_index_color& color_ref;
typedef pointer& parent_ref;
ordered_index_color& color(){return color_;}
ordered_index_color color()const{return color_;}
pointer& parent(){return parent_;}
pointer parent()const{return parent_;}
pointer& left(){return left_;}
pointer left()const{return left_;}
pointer& right(){return right_;}
pointer right()const{return right_;}
private:
ordered_index_color color_;
pointer parent_;
pointer left_;
pointer right_;
};
#if !defined(BOOST_MULTI_INDEX_DISABLE_COMPRESSED_ORDERED_INDEX_NODES)
/* If ordered_index_node_impl has even alignment, we can use the least
* significant bit of one of the ordered_index_node_impl pointers to
* store color information. This typically reduces the size of
* ordered_index_node_impl by 25%.
*/
#if defined(BOOST_MSVC)
/* This code casts pointers to an integer type that has been computed
* to be large enough to hold the pointer, however the metaprogramming
* logic is not always spotted by the VC++ code analyser that issues a
* long list of warnings.
*/
#pragma warning(push)
#pragma warning(disable:4312 4311)
#endif
template<typename AugmentPolicy,typename Allocator>
struct ordered_index_node_compressed_base
{
typedef ordered_index_node_impl<
AugmentPolicy,Allocator>* pointer;
typedef const ordered_index_node_impl<
AugmentPolicy,Allocator>* const_pointer;
struct color_ref
{
color_ref(uintptr_type* r_):r(r_){}
operator ordered_index_color()const
{
return ordered_index_color(*r&uintptr_type(1));
}
color_ref& operator=(ordered_index_color c)
{
*r&=~uintptr_type(1);
*r|=uintptr_type(c);
return *this;
}
color_ref& operator=(const color_ref& x)
{
return operator=(x.operator ordered_index_color());
}
private:
uintptr_type* r;
};
struct parent_ref
{
parent_ref(uintptr_type* r_):r(r_){}
operator pointer()const
{
return (pointer)(void*)(*r&~uintptr_type(1));
}
parent_ref& operator=(pointer p)
{
*r=((uintptr_type)(void*)p)|(*r&uintptr_type(1));
return *this;
}
parent_ref& operator=(const parent_ref& x)
{
return operator=(x.operator pointer());
}
pointer operator->()const
{
return operator pointer();
}
private:
uintptr_type* r;
};
color_ref color(){return color_ref(&parentcolor_);}
ordered_index_color color()const
{
return ordered_index_color(parentcolor_&uintptr_type(1));
}
parent_ref parent(){return parent_ref(&parentcolor_);}
pointer parent()const
{
return (pointer)(void*)(parentcolor_&~uintptr_type(1));
}
pointer& left(){return left_;}
pointer left()const{return left_;}
pointer& right(){return right_;}
pointer right()const{return right_;}
private:
uintptr_type parentcolor_;
pointer left_;
pointer right_;
};
#if defined(BOOST_MSVC)
#pragma warning(pop)
#endif
#endif
template<typename AugmentPolicy,typename Allocator>
struct ordered_index_node_impl_base:
#if !defined(BOOST_MULTI_INDEX_DISABLE_COMPRESSED_ORDERED_INDEX_NODES)
AugmentPolicy::template augmented_node<
typename mpl::if_c<
!(has_uintptr_type::value)||
(alignment_of<
ordered_index_node_compressed_base<AugmentPolicy,Allocator>
>::value%2)||
!(is_same<
typename boost::detail::allocator::rebind_to<
Allocator,
ordered_index_node_impl<AugmentPolicy,Allocator>
>::type::pointer,
ordered_index_node_impl<AugmentPolicy,Allocator>*>::value),
ordered_index_node_std_base<AugmentPolicy,Allocator>,
ordered_index_node_compressed_base<AugmentPolicy,Allocator>
>::type
>::type
#else
AugmentPolicy::template augmented_node<
ordered_index_node_std_base<AugmentPolicy,Allocator>
>::type
#endif
{};
template<typename AugmentPolicy,typename Allocator>
struct ordered_index_node_impl:
ordered_index_node_impl_base<AugmentPolicy,Allocator>
{
private:
typedef ordered_index_node_impl_base<AugmentPolicy,Allocator> super;
public:
typedef typename super::color_ref color_ref;
typedef typename super::parent_ref parent_ref;
typedef typename super::pointer pointer;
typedef typename super::const_pointer const_pointer;
/* interoperability with bidir_node_iterator */
static void increment(pointer& x)
{
if(x->right()!=pointer(0)){
x=x->right();
while(x->left()!=pointer(0))x=x->left();
}
else{
pointer y=x->parent();
while(x==y->right()){
x=y;
y=y->parent();
}
if(x->right()!=y)x=y;
}
}
static void decrement(pointer& x)
{
if(x->color()==red&&x->parent()->parent()==x){
x=x->right();
}
else if(x->left()!=pointer(0)){
pointer y=x->left();
while(y->right()!=pointer(0))y=y->right();
x=y;
}else{
pointer y=x->parent();
while(x==y->left()){
x=y;
y=y->parent();
}
x=y;
}
}
/* algorithmic stuff */
static void rotate_left(pointer x,parent_ref root)
{
pointer y=x->right();
x->right()=y->left();
if(y->left()!=pointer(0))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;
AugmentPolicy::rotate_left(x,y);
}
static pointer minimum(pointer x)
{
while(x->left()!=pointer(0))x=x->left();
return x;
}
static pointer maximum(pointer x)
{
while(x->right()!=pointer(0))x=x->right();
return x;
}
static void rotate_right(pointer x,parent_ref root)
{
pointer y=x->left();
x->left()=y->right();
if(y->right()!=pointer(0))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;
AugmentPolicy::rotate_right(x,y);
}
static void rebalance(pointer x,parent_ref root)
{
x->color()=red;
while(x!=root&&x->parent()->color()==red){
if(x->parent()==x->parent()->parent()->left()){
pointer y=x->parent()->parent()->right();
if(y!=pointer(0)&&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{
pointer y=x->parent()->parent()->left();
if(y!=pointer(0)&&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 void link(
pointer x,ordered_index_side side,pointer position,pointer header)
{
if(side==to_left){
position->left()=x; /* also makes leftmost=x when parent==header */
if(position==header){
header->parent()=x;
header->right()=x;
}
else if(position==header->left()){
header->left()=x; /* maintain leftmost pointing to min node */
}
}
else{
position->right()=x;
if(position==header->right()){
header->right()=x; /* maintain rightmost pointing to max node */
}
}
x->parent()=position;
x->left()=pointer(0);
x->right()=pointer(0);
AugmentPolicy::add(x,pointer(header->parent()));
ordered_index_node_impl::rebalance(x,header->parent());
}
static pointer rebalance_for_erase(
pointer z,parent_ref root,pointer& leftmost,pointer& rightmost)
{
pointer y=z;
pointer x=pointer(0);
pointer x_parent=pointer(0);
if(y->left()==pointer(0)){ /* z has at most one non-null child. y==z. */
x=y->right(); /* x might be null */
}
else{
if(y->right()==pointer(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()!=pointer(0))y=y->left();
x=y->right();
}
}
AugmentPolicy::remove(y,pointer(root));
if(y!=z){
AugmentPolicy::copy(z,y);
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!=pointer(0))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();
ordered_index_color c=y->color();
y->color()=z->color();
z->color()=c;
y=z; /* y now points to node to be actually deleted */
}
else{ /* y==z */
x_parent=y->parent();
if(x!=pointer(0))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()==pointer(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()==pointer(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==pointer(0)|| x->color()==black)){
if(x==x_parent->left()){
pointer 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()==pointer(0)||w->left()->color()==black) &&
(w->right()==pointer(0)||w->right()->color()==black)){
w->color()=red;
x=x_parent;
x_parent=x_parent->parent();
}
else{
if(w->right()==pointer(0 )
|| w->right()->color()==black){
if(w->left()!=pointer(0)) 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()!=pointer(0))w->right()->color()=black;
rotate_left(x_parent,root);
break;
}
}
else{ /* same as above,with right <-> left */
pointer 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()==pointer(0)||w->right()->color()==black) &&
(w->left()==pointer(0)||w->left()->color()==black)){
w->color()=red;
x=x_parent;
x_parent=x_parent->parent();
}
else{
if(w->left()==pointer(0)||w->left()->color()==black){
if(w->right()!=pointer(0))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()!=pointer(0))w->left()->color()=black;
rotate_right(x_parent,root);
break;
}
}
}
if(x!=pointer(0))x->color()=black;
}
return y;
}
static void restore(pointer x,pointer position,pointer header)
{
if(position->left()==pointer(0)||position->left()==header){
link(x,to_left,position,header);
}
else{
decrement(position);
link(x,to_right,position,header);
}
}
#if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING)
/* invariant stuff */
static std::size_t black_count(pointer node,pointer root)
{
if(node==pointer(0))return 0;
std::size_t sum=0;
for(;;){
if(node->color()==black)++sum;
if(node==root)break;
node=node->parent();
}
return sum;
}
#endif
};
template<typename AugmentPolicy,typename Super>
struct ordered_index_node_trampoline:
ordered_index_node_impl<
AugmentPolicy,
typename boost::detail::allocator::rebind_to<
typename Super::allocator_type,
char
>::type
>
{
typedef ordered_index_node_impl<
AugmentPolicy,
typename boost::detail::allocator::rebind_to<
typename Super::allocator_type,
char
>::type
> impl_type;
};
template<typename AugmentPolicy,typename Super>
struct ordered_index_node:
Super,ordered_index_node_trampoline<AugmentPolicy,Super>
{
private:
typedef ordered_index_node_trampoline<AugmentPolicy,Super> trampoline;
public:
typedef typename trampoline::impl_type impl_type;
typedef typename trampoline::color_ref impl_color_ref;
typedef typename trampoline::parent_ref impl_parent_ref;
typedef typename trampoline::pointer impl_pointer;
typedef typename trampoline::const_pointer const_impl_pointer;
impl_color_ref color(){return trampoline::color();}
ordered_index_color color()const{return trampoline::color();}
impl_parent_ref parent(){return trampoline::parent();}
impl_pointer parent()const{return trampoline::parent();}
impl_pointer& left(){return trampoline::left();}
impl_pointer left()const{return trampoline::left();}
impl_pointer& right(){return trampoline::right();}
impl_pointer right()const{return trampoline::right();}
impl_pointer impl()
{
return static_cast<impl_pointer>(
static_cast<impl_type*>(static_cast<trampoline*>(this)));
}
const_impl_pointer impl()const
{
return static_cast<const_impl_pointer>(
static_cast<const impl_type*>(static_cast<const trampoline*>(this)));
}
static ordered_index_node* from_impl(impl_pointer x)
{
return
static_cast<ordered_index_node*>(
static_cast<trampoline*>(
raw_ptr<impl_type*>(x)));
}
static const ordered_index_node* from_impl(const_impl_pointer x)
{
return
static_cast<const ordered_index_node*>(
static_cast<const trampoline*>(
raw_ptr<const impl_type*>(x)));
}
/* interoperability with bidir_node_iterator */
static void increment(ordered_index_node*& x)
{
impl_pointer xi=x->impl();
trampoline::increment(xi);
x=from_impl(xi);
}
static void decrement(ordered_index_node*& x)
{
impl_pointer xi=x->impl();
trampoline::decrement(xi);
x=from_impl(xi);
}
};
} /* namespace multi_index::detail */
} /* namespace multi_index */
} /* namespace boost */
#endif
@@ -0,0 +1,266 @@
/* Copyright 2003-2014 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*
* 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
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <boost/mpl/and.hpp>
#include <boost/multi_index/detail/promotes_arg.hpp>
#include <utility>
namespace boost{
namespace multi_index{
namespace detail{
/* Common code for index memfuns having templatized and
* non-templatized versions.
* Implementation note: When CompatibleKey is consistently promoted to
* KeyFromValue::result_type for comparison, the promotion is made once in
* advance to increase efficiency.
*/
template<
typename Node,typename KeyFromValue,
typename CompatibleKey,typename CompatibleCompare
>
inline Node* ordered_index_find(
Node* top,Node* y,const KeyFromValue& key,const CompatibleKey& x,
const CompatibleCompare& comp)
{
typedef typename KeyFromValue::result_type key_type;
return ordered_index_find(
top,y,key,x,comp,
mpl::and_<
promotes_1st_arg<CompatibleCompare,CompatibleKey,key_type>,
promotes_2nd_arg<CompatibleCompare,key_type,CompatibleKey> >());
}
template<
typename Node,typename KeyFromValue,
typename CompatibleCompare
>
inline Node* ordered_index_find(
Node* top,Node* y,const KeyFromValue& key,
const BOOST_DEDUCED_TYPENAME KeyFromValue::result_type& x,
const CompatibleCompare& comp,mpl::true_)
{
return ordered_index_find(top,y,key,x,comp,mpl::false_());
}
template<
typename Node,typename KeyFromValue,
typename CompatibleKey,typename CompatibleCompare
>
inline Node* ordered_index_find(
Node* top,Node* y,const KeyFromValue& key,const CompatibleKey& x,
const CompatibleCompare& comp,mpl::false_)
{
Node* y0=y;
while (top){
if(!comp(key(top->value()),x)){
y=top;
top=Node::from_impl(top->left());
}
else top=Node::from_impl(top->right());
}
return (y==y0||comp(x,key(y->value())))?y0:y;
}
template<
typename Node,typename KeyFromValue,
typename CompatibleKey,typename CompatibleCompare
>
inline Node* ordered_index_lower_bound(
Node* top,Node* y,const KeyFromValue& key,const CompatibleKey& x,
const CompatibleCompare& comp)
{
typedef typename KeyFromValue::result_type key_type;
return ordered_index_lower_bound(
top,y,key,x,comp,
promotes_2nd_arg<CompatibleCompare,key_type,CompatibleKey>());
}
template<
typename Node,typename KeyFromValue,
typename CompatibleCompare
>
inline Node* ordered_index_lower_bound(
Node* top,Node* y,const KeyFromValue& key,
const BOOST_DEDUCED_TYPENAME KeyFromValue::result_type& x,
const CompatibleCompare& comp,mpl::true_)
{
return ordered_index_lower_bound(top,y,key,x,comp,mpl::false_());
}
template<
typename Node,typename KeyFromValue,
typename CompatibleKey,typename CompatibleCompare
>
inline Node* ordered_index_lower_bound(
Node* top,Node* y,const KeyFromValue& key,const CompatibleKey& x,
const CompatibleCompare& comp,mpl::false_)
{
while(top){
if(!comp(key(top->value()),x)){
y=top;
top=Node::from_impl(top->left());
}
else top=Node::from_impl(top->right());
}
return y;
}
template<
typename Node,typename KeyFromValue,
typename CompatibleKey,typename CompatibleCompare
>
inline Node* ordered_index_upper_bound(
Node* top,Node* y,const KeyFromValue& key,const CompatibleKey& x,
const CompatibleCompare& comp)
{
typedef typename KeyFromValue::result_type key_type;
return ordered_index_upper_bound(
top,y,key,x,comp,
promotes_1st_arg<CompatibleCompare,CompatibleKey,key_type>());
}
template<
typename Node,typename KeyFromValue,
typename CompatibleCompare
>
inline Node* ordered_index_upper_bound(
Node* top,Node* y,const KeyFromValue& key,
const BOOST_DEDUCED_TYPENAME KeyFromValue::result_type& x,
const CompatibleCompare& comp,mpl::true_)
{
return ordered_index_upper_bound(top,y,key,x,comp,mpl::false_());
}
template<
typename Node,typename KeyFromValue,
typename CompatibleKey,typename CompatibleCompare
>
inline Node* ordered_index_upper_bound(
Node* top,Node* y,const KeyFromValue& key,const CompatibleKey& x,
const CompatibleCompare& comp,mpl::false_)
{
while(top){
if(comp(x,key(top->value()))){
y=top;
top=Node::from_impl(top->left());
}
else top=Node::from_impl(top->right());
}
return y;
}
template<
typename Node,typename KeyFromValue,
typename CompatibleKey,typename CompatibleCompare
>
inline std::pair<Node*,Node*> ordered_index_equal_range(
Node* top,Node* y,const KeyFromValue& key,const CompatibleKey& x,
const CompatibleCompare& comp)
{
typedef typename KeyFromValue::result_type key_type;
return ordered_index_equal_range(
top,y,key,x,comp,
mpl::and_<
promotes_1st_arg<CompatibleCompare,CompatibleKey,key_type>,
promotes_2nd_arg<CompatibleCompare,key_type,CompatibleKey> >());
}
template<
typename Node,typename KeyFromValue,
typename CompatibleCompare
>
inline std::pair<Node*,Node*> ordered_index_equal_range(
Node* top,Node* y,const KeyFromValue& key,
const BOOST_DEDUCED_TYPENAME KeyFromValue::result_type& x,
const CompatibleCompare& comp,mpl::true_)
{
return ordered_index_equal_range(top,y,key,x,comp,mpl::false_());
}
template<
typename Node,typename KeyFromValue,
typename CompatibleKey,typename CompatibleCompare
>
inline std::pair<Node*,Node*> ordered_index_equal_range(
Node* top,Node* y,const KeyFromValue& key,const CompatibleKey& x,
const CompatibleCompare& comp,mpl::false_)
{
while(top){
if(comp(key(top->value()),x)){
top=Node::from_impl(top->right());
}
else if(comp(x,key(top->value()))){
y=top;
top=Node::from_impl(top->left());
}
else{
return std::pair<Node*,Node*>(
ordered_index_lower_bound(
Node::from_impl(top->left()),top,key,x,comp,mpl::false_()),
ordered_index_upper_bound(
Node::from_impl(top->right()),y,key,x,comp,mpl::false_()));
}
}
return std::pair<Node*,Node*>(y,y);
}
} /* namespace multi_index::detail */
} /* namespace multi_index */
} /* namespace boost */
#endif
@@ -0,0 +1,83 @@
/* Copyright 2003-2017 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_PROMOTES_ARG_HPP
#define BOOST_MULTI_INDEX_DETAIL_PROMOTES_ARG_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <boost/detail/workaround.hpp>
/* Metafunctions to check if f(arg1,arg2) promotes either arg1 to the type of
* arg2 or viceversa. By default, (i.e. if it cannot be determined), no
* promotion is assumed.
*/
#if BOOST_WORKAROUND(BOOST_MSVC,<1400)
namespace boost{
namespace multi_index{
namespace detail{
template<typename F,typename Arg1,typename Arg2>
struct promotes_1st_arg:mpl::false_{};
template<typename F,typename Arg1,typename Arg2>
struct promotes_2nd_arg:mpl::false_{};
} /* namespace multi_index::detail */
} /* namespace multi_index */
} /* namespace boost */
#else
#include <boost/mpl/and.hpp>
#include <boost/mpl/bool.hpp>
#include <boost/mpl/not.hpp>
#include <boost/multi_index/detail/is_transparent.hpp>
#include <boost/type_traits/is_convertible.hpp>
namespace boost{
namespace multi_index{
namespace detail{
template<typename F,typename Arg1,typename Arg2>
struct promotes_1st_arg:
mpl::and_<
mpl::not_<is_transparent<F,Arg1,Arg2> >,
is_convertible<const Arg1,Arg2>,
is_transparent<F,Arg2,Arg2>
>
{};
template<typename F,typename Arg1,typename Arg2>
struct promotes_2nd_arg:
mpl::and_<
mpl::not_<is_transparent<F,Arg1,Arg2> >,
is_convertible<const Arg2,Arg1>,
is_transparent<F,Arg1,Arg1>
>
{};
} /* namespace multi_index::detail */
} /* namespace multi_index */
} /* namespace boost */
#endif
#endif
@@ -0,0 +1,52 @@
/* Copyright 2003-2015 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_RAW_PTR_HPP
#define BOOST_MULTI_INDEX_DETAIL_RAW_PTR_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <boost/mpl/bool.hpp>
#include <boost/type_traits/is_same.hpp>
namespace boost{
namespace multi_index{
namespace detail{
/* gets the underlying pointer of a pointer-like value */
template<typename RawPointer>
inline RawPointer raw_ptr(RawPointer const& p,mpl::true_)
{
return p;
}
template<typename RawPointer,typename Pointer>
inline RawPointer raw_ptr(Pointer const& p,mpl::false_)
{
return p==Pointer(0)?0:&*p;
}
template<typename RawPointer,typename Pointer>
inline RawPointer raw_ptr(Pointer const& p)
{
return raw_ptr<RawPointer>(p,is_same<RawPointer,Pointer>());
}
} /* namespace multi_index::detail */
} /* namespace multi_index */
} /* namespace boost */
#endif
@@ -0,0 +1,11 @@
/* Copyright 2003-2016 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#define BOOST_MULTI_INDEX_DETAIL_RESTORE_WSTRICT_ALIASING
#include <boost/multi_index/detail/ignore_wstrict_aliasing.hpp>
#undef BOOST_MULTI_INDEX_DETAIL_RESTORE_WSTRICT_ALIASING
@@ -0,0 +1,173 @@
/* Copyright 2003-2013 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_RND_INDEX_LOADER_HPP
#define BOOST_MULTI_INDEX_DETAIL_RND_INDEX_LOADER_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <algorithm>
#include <boost/detail/allocator_utilities.hpp>
#include <boost/multi_index/detail/auto_space.hpp>
#include <boost/multi_index/detail/rnd_index_ptr_array.hpp>
#include <boost/noncopyable.hpp>
#include <cstddef>
namespace boost{
namespace multi_index{
namespace detail{
/* This class implements a serialization rearranger for random access
* indices. In order to achieve O(n) performance, the following strategy
* is followed: the nodes of the index are handled as if in a bidirectional
* list, where the next pointers are stored in the original
* random_access_index_ptr_array and the prev pointers are stored in
* an auxiliary array. Rearranging of nodes in such a bidirectional list
* is constant time. Once all the arrangements are performed (on destruction
* time) the list is traversed in reverse order and
* pointers are swapped and set accordingly so that they recover its
* original semantics ( *(node->up())==node ) while retaining the
* new order.
*/
template<typename Allocator>
class random_access_index_loader_base:private noncopyable
{
protected:
typedef random_access_index_node_impl<
typename boost::detail::allocator::rebind_to<
Allocator,
char
>::type
> node_impl_type;
typedef typename node_impl_type::pointer node_impl_pointer;
typedef random_access_index_ptr_array<Allocator> ptr_array;
random_access_index_loader_base(const Allocator& al_,ptr_array& ptrs_):
al(al_),
ptrs(ptrs_),
header(*ptrs.end()),
prev_spc(al,0),
preprocessed(false)
{}
~random_access_index_loader_base()
{
if(preprocessed)
{
node_impl_pointer n=header;
next(n)=n;
for(std::size_t i=ptrs.size();i--;){
n=prev(n);
std::size_t d=position(n);
if(d!=i){
node_impl_pointer m=prev(next_at(i));
std::swap(m->up(),n->up());
next_at(d)=next_at(i);
std::swap(prev_at(d),prev_at(i));
}
next(n)=n;
}
}
}
void rearrange(node_impl_pointer position_,node_impl_pointer x)
{
preprocess(); /* only incur this penalty if rearrange() is ever called */
if(position_==node_impl_pointer(0))position_=header;
next(prev(x))=next(x);
prev(next(x))=prev(x);
prev(x)=position_;
next(x)=next(position_);
next(prev(x))=prev(next(x))=x;
}
private:
void preprocess()
{
if(!preprocessed){
/* get space for the auxiliary prev array */
auto_space<node_impl_pointer,Allocator> tmp(al,ptrs.size()+1);
prev_spc.swap(tmp);
/* prev_spc elements point to the prev nodes */
std::rotate_copy(
&*ptrs.begin(),&*ptrs.end(),&*ptrs.end()+1,&*prev_spc.data());
/* ptrs elements point to the next nodes */
std::rotate(&*ptrs.begin(),&*ptrs.begin()+1,&*ptrs.end()+1);
preprocessed=true;
}
}
std::size_t position(node_impl_pointer x)const
{
return (std::size_t)(x->up()-ptrs.begin());
}
node_impl_pointer& next_at(std::size_t n)const
{
return *ptrs.at(n);
}
node_impl_pointer& prev_at(std::size_t n)const
{
return *(prev_spc.data()+n);
}
node_impl_pointer& next(node_impl_pointer x)const
{
return *(x->up());
}
node_impl_pointer& prev(node_impl_pointer x)const
{
return prev_at(position(x));
}
Allocator al;
ptr_array& ptrs;
node_impl_pointer header;
auto_space<node_impl_pointer,Allocator> prev_spc;
bool preprocessed;
};
template<typename Node,typename Allocator>
class random_access_index_loader:
private random_access_index_loader_base<Allocator>
{
typedef random_access_index_loader_base<Allocator> super;
typedef typename super::node_impl_pointer node_impl_pointer;
typedef typename super::ptr_array ptr_array;
public:
random_access_index_loader(const Allocator& al_,ptr_array& ptrs_):
super(al_,ptrs_)
{}
void rearrange(Node* position_,Node *x)
{
super::rearrange(
position_?position_->impl():node_impl_pointer(0),x->impl());
}
};
} /* namespace multi_index::detail */
} /* namespace multi_index */
} /* namespace boost */
#endif
@@ -0,0 +1,273 @@
/* Copyright 2003-2015 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_RND_INDEX_NODE_HPP
#define BOOST_MULTI_INDEX_DETAIL_RND_INDEX_NODE_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <algorithm>
#include <boost/detail/allocator_utilities.hpp>
#include <boost/integer/common_factor_rt.hpp>
#include <boost/multi_index/detail/raw_ptr.hpp>
#include <cstddef>
#include <functional>
namespace boost{
namespace multi_index{
namespace detail{
template<typename Allocator>
struct random_access_index_node_impl
{
typedef typename
boost::detail::allocator::rebind_to<
Allocator,random_access_index_node_impl
>::type::pointer pointer;
typedef typename
boost::detail::allocator::rebind_to<
Allocator,random_access_index_node_impl
>::type::const_pointer const_pointer;
typedef typename
boost::detail::allocator::rebind_to<
Allocator,pointer
>::type::pointer ptr_pointer;
ptr_pointer& up(){return up_;}
ptr_pointer up()const{return up_;}
/* interoperability with rnd_node_iterator */
static void increment(pointer& x)
{
x=*(x->up()+1);
}
static void decrement(pointer& x)
{
x=*(x->up()-1);
}
static void advance(pointer& x,std::ptrdiff_t n)
{
x=*(x->up()+n);
}
static std::ptrdiff_t distance(pointer x,pointer y)
{
return y->up()-x->up();
}
/* algorithmic stuff */
static void relocate(ptr_pointer pos,ptr_pointer x)
{
pointer n=*x;
if(x<pos){
extract(x,pos);
*(pos-1)=n;
n->up()=pos-1;
}
else{
while(x!=pos){
*x=*(x-1);
(*x)->up()=x;
--x;
}
*pos=n;
n->up()=pos;
}
};
static void relocate(ptr_pointer pos,ptr_pointer first,ptr_pointer last)
{
ptr_pointer begin,middle,end;
if(pos<first){
begin=pos;
middle=first;
end=last;
}
else{
begin=first;
middle=last;
end=pos;
}
std::ptrdiff_t n=end-begin;
std::ptrdiff_t m=middle-begin;
std::ptrdiff_t n_m=n-m;
std::ptrdiff_t p=integer::gcd(n,m);
for(std::ptrdiff_t i=0;i<p;++i){
pointer tmp=begin[i];
for(std::ptrdiff_t j=i,k;;){
if(j<n_m)k=j+m;
else k=j-n_m;
if(k==i){
*(begin+j)=tmp;
(*(begin+j))->up()=begin+j;
break;
}
else{
*(begin+j)=*(begin+k);
(*(begin+j))->up()=begin+j;
}
if(k<n_m)j=k+m;
else j=k-n_m;
if(j==i){
*(begin+k)=tmp;
(*(begin+k))->up()=begin+k;
break;
}
else{
*(begin+k)=*(begin+j);
(*(begin+k))->up()=begin+k;
}
}
}
};
static void extract(ptr_pointer x,ptr_pointer pend)
{
--pend;
while(x!=pend){
*x=*(x+1);
(*x)->up()=x;
++x;
}
}
static void transfer(
ptr_pointer pbegin0,ptr_pointer pend0,ptr_pointer pbegin1)
{
while(pbegin0!=pend0){
*pbegin1=*pbegin0++;
(*pbegin1)->up()=pbegin1;
++pbegin1;
}
}
static void reverse(ptr_pointer pbegin,ptr_pointer pend)
{
std::ptrdiff_t d=(pend-pbegin)/2;
for(std::ptrdiff_t i=0;i<d;++i){
std::swap(*pbegin,*--pend);
(*pbegin)->up()=pbegin;
(*pend)->up()=pend;
++pbegin;
}
}
private:
ptr_pointer up_;
};
template<typename Super>
struct random_access_index_node_trampoline:
random_access_index_node_impl<
typename boost::detail::allocator::rebind_to<
typename Super::allocator_type,
char
>::type
>
{
typedef random_access_index_node_impl<
typename boost::detail::allocator::rebind_to<
typename Super::allocator_type,
char
>::type
> impl_type;
};
template<typename Super>
struct random_access_index_node:
Super,random_access_index_node_trampoline<Super>
{
private:
typedef random_access_index_node_trampoline<Super> trampoline;
public:
typedef typename trampoline::impl_type impl_type;
typedef typename trampoline::pointer impl_pointer;
typedef typename trampoline::const_pointer const_impl_pointer;
typedef typename trampoline::ptr_pointer impl_ptr_pointer;
impl_ptr_pointer& up(){return trampoline::up();}
impl_ptr_pointer up()const{return trampoline::up();}
impl_pointer impl()
{
return static_cast<impl_pointer>(
static_cast<impl_type*>(static_cast<trampoline*>(this)));
}
const_impl_pointer impl()const
{
return static_cast<const_impl_pointer>(
static_cast<const impl_type*>(static_cast<const trampoline*>(this)));
}
static random_access_index_node* from_impl(impl_pointer x)
{
return
static_cast<random_access_index_node*>(
static_cast<trampoline*>(
raw_ptr<impl_type*>(x)));
}
static const random_access_index_node* from_impl(const_impl_pointer x)
{
return
static_cast<const random_access_index_node*>(
static_cast<const trampoline*>(
raw_ptr<const impl_type*>(x)));
}
/* interoperability with rnd_node_iterator */
static void increment(random_access_index_node*& x)
{
impl_pointer xi=x->impl();
trampoline::increment(xi);
x=from_impl(xi);
}
static void decrement(random_access_index_node*& x)
{
impl_pointer xi=x->impl();
trampoline::decrement(xi);
x=from_impl(xi);
}
static void advance(random_access_index_node*& x,std::ptrdiff_t n)
{
impl_pointer xi=x->impl();
trampoline::advance(xi,n);
x=from_impl(xi);
}
static std::ptrdiff_t distance(
random_access_index_node* x,random_access_index_node* y)
{
return trampoline::distance(x->impl(),y->impl());
}
};
} /* namespace multi_index::detail */
} /* namespace multi_index */
} /* namespace boost */
#endif
@@ -0,0 +1,203 @@
/* Copyright 2003-2015 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_RND_INDEX_OPS_HPP
#define BOOST_MULTI_INDEX_DETAIL_RND_INDEX_OPS_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <algorithm>
#include <boost/multi_index/detail/rnd_index_ptr_array.hpp>
namespace boost{
namespace multi_index{
namespace detail{
/* Common code for random_access_index memfuns having templatized and
* non-templatized versions.
*/
template<typename Node,typename Allocator,typename Predicate>
Node* random_access_index_remove(
random_access_index_ptr_array<Allocator>& ptrs,Predicate pred)
{
typedef typename Node::value_type value_type;
typedef typename Node::impl_ptr_pointer impl_ptr_pointer;
impl_ptr_pointer first=ptrs.begin(),
res=first,
last=ptrs.end();
for(;first!=last;++first){
if(!pred(
const_cast<const value_type&>(Node::from_impl(*first)->value()))){
if(first!=res){
std::swap(*first,*res);
(*first)->up()=first;
(*res)->up()=res;
}
++res;
}
}
return Node::from_impl(*res);
}
template<typename Node,typename Allocator,class BinaryPredicate>
Node* random_access_index_unique(
random_access_index_ptr_array<Allocator>& ptrs,BinaryPredicate binary_pred)
{
typedef typename Node::value_type value_type;
typedef typename Node::impl_ptr_pointer impl_ptr_pointer;
impl_ptr_pointer first=ptrs.begin(),
res=first,
last=ptrs.end();
if(first!=last){
for(;++first!=last;){
if(!binary_pred(
const_cast<const value_type&>(Node::from_impl(*res)->value()),
const_cast<const value_type&>(Node::from_impl(*first)->value()))){
++res;
if(first!=res){
std::swap(*first,*res);
(*first)->up()=first;
(*res)->up()=res;
}
}
}
++res;
}
return Node::from_impl(*res);
}
template<typename Node,typename Allocator,typename Compare>
void random_access_index_inplace_merge(
const Allocator& al,
random_access_index_ptr_array<Allocator>& ptrs,
BOOST_DEDUCED_TYPENAME Node::impl_ptr_pointer first1,Compare comp)
{
typedef typename Node::value_type value_type;
typedef typename Node::impl_pointer impl_pointer;
typedef typename Node::impl_ptr_pointer impl_ptr_pointer;
auto_space<impl_pointer,Allocator> spc(al,ptrs.size());
impl_ptr_pointer first0=ptrs.begin(),
last0=first1,
last1=ptrs.end(),
out=spc.data();
while(first0!=last0&&first1!=last1){
if(comp(
const_cast<const value_type&>(Node::from_impl(*first1)->value()),
const_cast<const value_type&>(Node::from_impl(*first0)->value()))){
*out++=*first1++;
}
else{
*out++=*first0++;
}
}
std::copy(&*first0,&*last0,&*out);
std::copy(&*first1,&*last1,&*out);
first1=ptrs.begin();
out=spc.data();
while(first1!=last1){
*first1=*out++;
(*first1)->up()=first1;
++first1;
}
}
/* sorting */
/* auxiliary stuff */
template<typename Node,typename Compare>
struct random_access_index_sort_compare
{
typedef typename Node::impl_pointer first_argument_type;
typedef typename Node::impl_pointer second_argument_type;
typedef bool result_type;
random_access_index_sort_compare(Compare comp_=Compare()):comp(comp_){}
bool operator()(
typename Node::impl_pointer x,typename Node::impl_pointer y)const
{
typedef typename Node::value_type value_type;
return comp(
const_cast<const value_type&>(Node::from_impl(x)->value()),
const_cast<const value_type&>(Node::from_impl(y)->value()));
}
private:
Compare comp;
};
template<typename Node,typename Allocator,class Compare>
void random_access_index_sort(
const Allocator& al,
random_access_index_ptr_array<Allocator>& ptrs,
Compare comp)
{
/* The implementation is extremely simple: an auxiliary
* array of pointers is sorted using stdlib facilities and
* then used to rearrange the index. This is suboptimal
* in space and time, but has some advantages over other
* possible approaches:
* - Use std::stable_sort() directly on ptrs using some
* special iterator in charge of maintaining pointers
* and up() pointers in sync: we cannot guarantee
* preservation of the container invariants in the face of
* exceptions, if, for instance, std::stable_sort throws
* when ptrs transitorily contains duplicate elements.
* - Rewrite the internal algorithms of std::stable_sort
* adapted for this case: besides being a fair amount of
* work, making a stable sort compatible with Boost.MultiIndex
* invariants (basically, no duplicates or missing elements
* even if an exception is thrown) is complicated, error-prone
* and possibly won't perform much better than the
* solution adopted.
*/
if(ptrs.size()<=1)return;
typedef typename Node::impl_pointer impl_pointer;
typedef typename Node::impl_ptr_pointer impl_ptr_pointer;
typedef random_access_index_sort_compare<
Node,Compare> ptr_compare;
impl_ptr_pointer first=ptrs.begin();
impl_ptr_pointer last=ptrs.end();
auto_space<
impl_pointer,
Allocator> spc(al,ptrs.size());
impl_ptr_pointer buf=spc.data();
std::copy(&*first,&*last,&*buf);
std::stable_sort(&*buf,&*buf+ptrs.size(),ptr_compare(comp));
while(first!=last){
*first=*buf++;
(*first)->up()=first;
++first;
}
}
} /* namespace multi_index::detail */
} /* namespace multi_index */
} /* namespace boost */
#endif
@@ -0,0 +1,144 @@
/* Copyright 2003-2013 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_RND_INDEX_PTR_ARRAY_HPP
#define BOOST_MULTI_INDEX_DETAIL_RND_INDEX_PTR_ARRAY_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <algorithm>
#include <boost/detail/allocator_utilities.hpp>
#include <boost/multi_index/detail/auto_space.hpp>
#include <boost/multi_index/detail/rnd_index_node.hpp>
#include <boost/noncopyable.hpp>
#include <cstddef>
namespace boost{
namespace multi_index{
namespace detail{
/* pointer structure for use by random access indices */
template<typename Allocator>
class random_access_index_ptr_array:private noncopyable
{
typedef random_access_index_node_impl<
typename boost::detail::allocator::rebind_to<
Allocator,
char
>::type
> node_impl_type;
public:
typedef typename node_impl_type::pointer value_type;
typedef typename boost::detail::allocator::rebind_to<
Allocator,value_type
>::type::pointer pointer;
random_access_index_ptr_array(
const Allocator& al,value_type end_,std::size_t sz):
size_(sz),
capacity_(sz),
spc(al,capacity_+1)
{
*end()=end_;
end_->up()=end();
}
std::size_t size()const{return size_;}
std::size_t capacity()const{return capacity_;}
void room_for_one()
{
if(size_==capacity_){
reserve(capacity_<=10?15:capacity_+capacity_/2);
}
}
void reserve(std::size_t c)
{
if(c>capacity_)set_capacity(c);
}
void shrink_to_fit()
{
if(capacity_>size_)set_capacity(size_);
}
pointer begin()const{return ptrs();}
pointer end()const{return ptrs()+size_;}
pointer at(std::size_t n)const{return ptrs()+n;}
void push_back(value_type x)
{
*(end()+1)=*end();
(*(end()+1))->up()=end()+1;
*end()=x;
(*end())->up()=end();
++size_;
}
void erase(value_type x)
{
node_impl_type::extract(x->up(),end()+1);
--size_;
}
void clear()
{
*begin()=*end();
(*begin())->up()=begin();
size_=0;
}
void swap(random_access_index_ptr_array& x)
{
std::swap(size_,x.size_);
std::swap(capacity_,x.capacity_);
spc.swap(x.spc);
}
private:
std::size_t size_;
std::size_t capacity_;
auto_space<value_type,Allocator> spc;
pointer ptrs()const
{
return spc.data();
}
void set_capacity(std::size_t c)
{
auto_space<value_type,Allocator> spc1(spc.get_allocator(),c+1);
node_impl_type::transfer(begin(),end()+1,spc1.data());
spc.swap(spc1);
capacity_=c;
}
};
template<typename Allocator>
void swap(
random_access_index_ptr_array<Allocator>& x,
random_access_index_ptr_array<Allocator>& y)
{
x.swap(y);
}
} /* namespace multi_index::detail */
} /* namespace multi_index */
} /* namespace boost */
#endif
@@ -0,0 +1,140 @@
/* Copyright 2003-2014 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_RND_NODE_ITERATOR_HPP
#define BOOST_MULTI_INDEX_DETAIL_RND_NODE_ITERATOR_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <boost/operators.hpp>
#if !defined(BOOST_MULTI_INDEX_DISABLE_SERIALIZATION)
#include <boost/serialization/nvp.hpp>
#include <boost/serialization/split_member.hpp>
#endif
namespace boost{
namespace multi_index{
namespace detail{
/* Iterator class for node-based indices with random access iterators. */
template<typename Node>
class rnd_node_iterator:
public random_access_iterator_helper<
rnd_node_iterator<Node>,
typename Node::value_type,
std::ptrdiff_t,
const typename Node::value_type*,
const typename Node::value_type&>
{
public:
/* coverity[uninit_ctor]: suppress warning */
rnd_node_iterator(){}
explicit rnd_node_iterator(Node* node_):node(node_){}
const typename Node::value_type& operator*()const
{
return node->value();
}
rnd_node_iterator& operator++()
{
Node::increment(node);
return *this;
}
rnd_node_iterator& operator--()
{
Node::decrement(node);
return *this;
}
rnd_node_iterator& operator+=(std::ptrdiff_t n)
{
Node::advance(node,n);
return *this;
}
rnd_node_iterator& operator-=(std::ptrdiff_t n)
{
Node::advance(node,-n);
return *this;
}
#if !defined(BOOST_MULTI_INDEX_DISABLE_SERIALIZATION)
/* Serialization. As for why the following is public,
* see explanation in safe_mode_iterator notes in safe_mode.hpp.
*/
BOOST_SERIALIZATION_SPLIT_MEMBER()
typedef typename Node::base_type node_base_type;
template<class Archive>
void save(Archive& ar,const unsigned int)const
{
node_base_type* bnode=node;
ar<<serialization::make_nvp("pointer",bnode);
}
template<class Archive>
void load(Archive& ar,const unsigned int)
{
node_base_type* bnode;
ar>>serialization::make_nvp("pointer",bnode);
node=static_cast<Node*>(bnode);
}
#endif
/* get_node is not to be used by the user */
typedef Node node_type;
Node* get_node()const{return node;}
private:
Node* node;
};
template<typename Node>
bool operator==(
const rnd_node_iterator<Node>& x,
const rnd_node_iterator<Node>& y)
{
return x.get_node()==y.get_node();
}
template<typename Node>
bool operator<(
const rnd_node_iterator<Node>& x,
const rnd_node_iterator<Node>& y)
{
return Node::distance(x.get_node(),y.get_node())>0;
}
template<typename Node>
std::ptrdiff_t operator-(
const rnd_node_iterator<Node>& x,
const rnd_node_iterator<Node>& y)
{
return Node::distance(y.get_node(),x.get_node());
}
} /* namespace multi_index::detail */
} /* namespace multi_index */
} /* namespace boost */
#endif
@@ -0,0 +1,300 @@
/* Copyright 2003-2017 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_RNK_INDEX_OPS_HPP
#define BOOST_MULTI_INDEX_DETAIL_RNK_INDEX_OPS_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <boost/mpl/and.hpp>
#include <boost/multi_index/detail/promotes_arg.hpp>
#include <cstddef>
#include <utility>
namespace boost{
namespace multi_index{
namespace detail{
/* Common code for ranked_index memfuns having templatized and
* non-templatized versions.
*/
template<typename Pointer>
inline std::size_t ranked_node_size(Pointer x)
{
return x!=Pointer(0)?x->size:0;
}
template<typename Pointer>
inline Pointer ranked_index_nth(std::size_t n,Pointer end_)
{
Pointer top=end_->parent();
if(top==Pointer(0)||n>=top->size)return end_;
for(;;){
std::size_t s=ranked_node_size(top->left());
if(n==s)return top;
if(n<s)top=top->left();
else{
top=top->right();
n-=s+1;
}
}
}
template<typename Pointer>
inline std::size_t ranked_index_rank(Pointer x,Pointer end_)
{
Pointer top=end_->parent();
if(top==Pointer(0))return 0;
if(x==end_)return top->size;
std::size_t s=ranked_node_size(x->left());
while(x!=top){
Pointer z=x->parent();
if(x==z->right()){
s+=ranked_node_size(z->left())+1;
}
x=z;
}
return s;
}
template<
typename Node,typename KeyFromValue,
typename CompatibleKey,typename CompatibleCompare
>
inline std::size_t ranked_index_find_rank(
Node* top,Node* y,const KeyFromValue& key,const CompatibleKey& x,
const CompatibleCompare& comp)
{
typedef typename KeyFromValue::result_type key_type;
return ranked_index_find_rank(
top,y,key,x,comp,
mpl::and_<
promotes_1st_arg<CompatibleCompare,CompatibleKey,key_type>,
promotes_2nd_arg<CompatibleCompare,key_type,CompatibleKey> >());
}
template<
typename Node,typename KeyFromValue,
typename CompatibleCompare
>
inline std::size_t ranked_index_find_rank(
Node* top,Node* y,const KeyFromValue& key,
const BOOST_DEDUCED_TYPENAME KeyFromValue::result_type& x,
const CompatibleCompare& comp,mpl::true_)
{
return ranked_index_find_rank(top,y,key,x,comp,mpl::false_());
}
template<
typename Node,typename KeyFromValue,
typename CompatibleKey,typename CompatibleCompare
>
inline std::size_t ranked_index_find_rank(
Node* top,Node* y,const KeyFromValue& key,const CompatibleKey& x,
const CompatibleCompare& comp,mpl::false_)
{
if(!top)return 0;
std::size_t s=top->impl()->size,
s0=s;
Node* y0=y;
do{
if(!comp(key(top->value()),x)){
y=top;
s-=ranked_node_size(y->right())+1;
top=Node::from_impl(top->left());
}
else top=Node::from_impl(top->right());
}while(top);
return (y==y0||comp(x,key(y->value())))?s0:s;
}
template<
typename Node,typename KeyFromValue,
typename CompatibleKey,typename CompatibleCompare
>
inline std::size_t ranked_index_lower_bound_rank(
Node* top,Node* y,const KeyFromValue& key,const CompatibleKey& x,
const CompatibleCompare& comp)
{
typedef typename KeyFromValue::result_type key_type;
return ranked_index_lower_bound_rank(
top,y,key,x,comp,
promotes_2nd_arg<CompatibleCompare,key_type,CompatibleKey>());
}
template<
typename Node,typename KeyFromValue,
typename CompatibleCompare
>
inline std::size_t ranked_index_lower_bound_rank(
Node* top,Node* y,const KeyFromValue& key,
const BOOST_DEDUCED_TYPENAME KeyFromValue::result_type& x,
const CompatibleCompare& comp,mpl::true_)
{
return ranked_index_lower_bound_rank(top,y,key,x,comp,mpl::false_());
}
template<
typename Node,typename KeyFromValue,
typename CompatibleKey,typename CompatibleCompare
>
inline std::size_t ranked_index_lower_bound_rank(
Node* top,Node* y,const KeyFromValue& key,const CompatibleKey& x,
const CompatibleCompare& comp,mpl::false_)
{
if(!top)return 0;
std::size_t s=top->impl()->size;
do{
if(!comp(key(top->value()),x)){
y=top;
s-=ranked_node_size(y->right())+1;
top=Node::from_impl(top->left());
}
else top=Node::from_impl(top->right());
}while(top);
return s;
}
template<
typename Node,typename KeyFromValue,
typename CompatibleKey,typename CompatibleCompare
>
inline std::size_t ranked_index_upper_bound_rank(
Node* top,Node* y,const KeyFromValue& key,const CompatibleKey& x,
const CompatibleCompare& comp)
{
typedef typename KeyFromValue::result_type key_type;
return ranked_index_upper_bound_rank(
top,y,key,x,comp,
promotes_1st_arg<CompatibleCompare,CompatibleKey,key_type>());
}
template<
typename Node,typename KeyFromValue,
typename CompatibleCompare
>
inline std::size_t ranked_index_upper_bound_rank(
Node* top,Node* y,const KeyFromValue& key,
const BOOST_DEDUCED_TYPENAME KeyFromValue::result_type& x,
const CompatibleCompare& comp,mpl::true_)
{
return ranked_index_upper_bound_rank(top,y,key,x,comp,mpl::false_());
}
template<
typename Node,typename KeyFromValue,
typename CompatibleKey,typename CompatibleCompare
>
inline std::size_t ranked_index_upper_bound_rank(
Node* top,Node* y,const KeyFromValue& key,const CompatibleKey& x,
const CompatibleCompare& comp,mpl::false_)
{
if(!top)return 0;
std::size_t s=top->impl()->size;
do{
if(comp(x,key(top->value()))){
y=top;
s-=ranked_node_size(y->right())+1;
top=Node::from_impl(top->left());
}
else top=Node::from_impl(top->right());
}while(top);
return s;
}
template<
typename Node,typename KeyFromValue,
typename CompatibleKey,typename CompatibleCompare
>
inline std::pair<std::size_t,std::size_t> ranked_index_equal_range_rank(
Node* top,Node* y,const KeyFromValue& key,const CompatibleKey& x,
const CompatibleCompare& comp)
{
typedef typename KeyFromValue::result_type key_type;
return ranked_index_equal_range_rank(
top,y,key,x,comp,
mpl::and_<
promotes_1st_arg<CompatibleCompare,CompatibleKey,key_type>,
promotes_2nd_arg<CompatibleCompare,key_type,CompatibleKey> >());
}
template<
typename Node,typename KeyFromValue,
typename CompatibleCompare
>
inline std::pair<std::size_t,std::size_t> ranked_index_equal_range_rank(
Node* top,Node* y,const KeyFromValue& key,
const BOOST_DEDUCED_TYPENAME KeyFromValue::result_type& x,
const CompatibleCompare& comp,mpl::true_)
{
return ranked_index_equal_range_rank(top,y,key,x,comp,mpl::false_());
}
template<
typename Node,typename KeyFromValue,
typename CompatibleKey,typename CompatibleCompare
>
inline std::pair<std::size_t,std::size_t> ranked_index_equal_range_rank(
Node* top,Node* y,const KeyFromValue& key,const CompatibleKey& x,
const CompatibleCompare& comp,mpl::false_)
{
if(!top)return std::pair<std::size_t,std::size_t>(0,0);
std::size_t s=top->impl()->size;
do{
if(comp(key(top->value()),x)){
top=Node::from_impl(top->right());
}
else if(comp(x,key(top->value()))){
y=top;
s-=ranked_node_size(y->right())+1;
top=Node::from_impl(top->left());
}
else{
return std::pair<std::size_t,std::size_t>(
s-top->impl()->size+
ranked_index_lower_bound_rank(
Node::from_impl(top->left()),top,key,x,comp,mpl::false_()),
s-ranked_node_size(top->right())+
ranked_index_upper_bound_rank(
Node::from_impl(top->right()),y,key,x,comp,mpl::false_()));
}
}while(top);
return std::pair<std::size_t,std::size_t>(s,s);
}
} /* namespace multi_index::detail */
} /* namespace multi_index */
} /* namespace boost */
#endif
@@ -0,0 +1,588 @@
/* Copyright 2003-2013 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_SAFE_MODE_HPP
#define BOOST_MULTI_INDEX_DETAIL_SAFE_MODE_HPP
#if defined(_MSC_VER)
#pragma once
#endif
/* 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<Container>, and their corresponding iterators
* are wrapped with 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.
* Safe mode iterators automatically check that only proper operations
* are performed on them: for instance, an invalid iterator cannot be
* dereferenced. Additionally, a set of utilty macros and functions are
* provided that serve to implement preconditions and cooperate with
* the framework within the container.
* Iterators can also be unchecked, i.e. they do not have info about
* which container they belong in. This situation arises when the iterator
* is restored from a serialization archive: only information on the node
* is available, and it is not possible to determine to which container
* the iterator is associated to. The only sensible policy is to assume
* unchecked iterators are valid, though this can certainly generate false
* positive safe mode checks.
* This is not a full-fledged safe mode framework, and is only intended
* for use within the limits of Boost.MultiIndex.
*/
/* Assertion macros. These resolve to no-ops if
* !defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE).
*/
#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 <boost/assert.hpp>
#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_IN_BOUNDS(it,n) \
BOOST_MULTI_INDEX_SAFE_MODE_ASSERT( \
safe_mode::check_in_bounds(it,n), \
safe_mode::out_of_bounds);
#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);
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <algorithm>
#include <boost/detail/iterator.hpp>
#include <boost/multi_index/detail/access_specifier.hpp>
#include <boost/multi_index/detail/iter_adaptor.hpp>
#include <boost/multi_index/safe_mode_errors.hpp>
#include <boost/noncopyable.hpp>
#if !defined(BOOST_MULTI_INDEX_DISABLE_SERIALIZATION)
#include <boost/serialization/split_member.hpp>
#include <boost/serialization/version.hpp>
#endif
#if defined(BOOST_HAS_THREADS)
#include <boost/detail/lightweight_mutex.hpp>
#endif
namespace boost{
namespace multi_index{
namespace safe_mode{
/* Checking routines. Assume the best for unchecked iterators
* (i.e. they pass the checking when there is not enough info
* to know.)
*/
template<typename Iterator>
inline bool check_valid_iterator(const Iterator& it)
{
return it.valid()||it.unchecked();
}
template<typename Iterator>
inline bool check_dereferenceable_iterator(const Iterator& it)
{
return (it.valid()&&it!=it.owner()->end())||it.unchecked();
}
template<typename Iterator>
inline bool check_incrementable_iterator(const Iterator& it)
{
return (it.valid()&&it!=it.owner()->end())||it.unchecked();
}
template<typename Iterator>
inline bool check_decrementable_iterator(const Iterator& it)
{
return (it.valid()&&it!=it.owner()->begin())||it.unchecked();
}
template<typename Iterator>
inline bool check_is_owner(
const Iterator& it,const typename Iterator::container_type& cont)
{
return (it.valid()&&it.owner()==&cont)||it.unchecked();
}
template<typename Iterator>
inline bool check_same_owner(const Iterator& it0,const Iterator& it1)
{
return (it0.valid()&&it1.valid()&&it0.owner()==it1.owner())||
it0.unchecked()||it1.unchecked();
}
template<typename Iterator>
inline bool check_valid_range(const Iterator& it0,const Iterator& it1)
{
if(!check_same_owner(it0,it1))return false;
if(it0.valid()){
Iterator last=it0.owner()->end();
if(it1==last)return true;
for(Iterator first=it0;first!=last;++first){
if(first==it1)return true;
}
return false;
}
return true;
}
template<typename Iterator>
inline bool check_outside_range(
const Iterator& it,const Iterator& it0,const Iterator& it1)
{
if(!check_same_owner(it0,it1))return false;
if(it0.valid()){
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;
}
return true;
}
template<typename Iterator,typename Difference>
inline bool check_in_bounds(const Iterator& it,Difference n)
{
if(it.unchecked())return true;
if(!it.valid()) return false;
if(n>0) return it.owner()->end()-it>=n;
else return it.owner()->begin()-it<=n;
}
template<typename Container>
inline bool check_different_container(
const Container& cont0,const Container& cont1)
{
return &cont0!=&cont1;
}
/* Invalidates all iterators equivalent to that given. Safe containers
* must call this when deleting elements: the safe mode framework cannot
* perform this operation automatically without outside help.
*/
template<typename Iterator>
inline void detach_equivalent_iterators(Iterator& it)
{
if(it.valid()){
{
#if defined(BOOST_HAS_THREADS)
boost::detail::lightweight_mutex::scoped_lock lock(it.cont->mutex);
#endif
Iterator *prev_,*next_;
for(
prev_=static_cast<Iterator*>(&it.cont->header);
(next_=static_cast<Iterator*>(prev_->next))!=0;){
if(next_!=&it&&*next_==it){
prev_->next=next_->next;
next_->cont=0;
}
else prev_=next_;
}
}
it.detach();
}
}
template<typename Container> class safe_container; /* fwd decl. */
} /* namespace multi_index::safe_mode */
namespace detail{
class safe_container_base; /* fwd decl. */
class safe_iterator_base
{
public:
bool valid()const{return cont!=0;}
bool unchecked()const{return unchecked_;}
inline void detach();
void uncheck()
{
detach();
unchecked_=true;
}
protected:
safe_iterator_base():cont(0),next(0),unchecked_(false){}
explicit safe_iterator_base(safe_container_base* cont_):
unchecked_(false)
{
attach(cont_);
}
safe_iterator_base(const safe_iterator_base& it):
unchecked_(it.unchecked_)
{
attach(it.cont);
}
safe_iterator_base& operator=(const safe_iterator_base& it)
{
unchecked_=it.unchecked_;
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<typename> friend class safe_mode::safe_container;
template<typename Iterator> friend
void safe_mode::detach_equivalent_iterators(Iterator&);
#endif
inline void attach(safe_container_base* cont_);
safe_container_base* cont;
safe_iterator_base* next;
bool unchecked_;
};
class safe_container_base:private noncopyable
{
public:
safe_container_base(){}
BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
friend class safe_iterator_base;
#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
template<typename Iterator> friend
void safe_mode::detach_equivalent_iterators(Iterator&);
#endif
~safe_container_base()
{
/* Detaches all remaining iterators, which by now will
* be those pointing to the end of the container.
*/
for(safe_iterator_base* it=header.next;it;it=it->next)it->cont=0;
header.next=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);
}
safe_iterator_base header;
#if defined(BOOST_HAS_THREADS)
boost::detail::lightweight_mutex mutex;
#endif
};
void safe_iterator_base::attach(safe_container_base* cont_)
{
cont=cont_;
if(cont){
#if defined(BOOST_HAS_THREADS)
boost::detail::lightweight_mutex::scoped_lock lock(cont->mutex);
#endif
next=cont->header.next;
cont->header.next=this;
}
}
void safe_iterator_base::detach()
{
if(cont){
#if defined(BOOST_HAS_THREADS)
boost::detail::lightweight_mutex::scoped_lock lock(cont->mutex);
#endif
safe_iterator_base *prev_,*next_;
for(prev_=&cont->header;(next_=prev_->next)!=this;prev_=next_){}
prev_->next=next;
cont=0;
}
}
} /* namespace multi_index::detail */
namespace safe_mode{
/* In order to enable safe mode on a container:
* - The container must derive from safe_container<container_type>,
* - iterators must be generated via safe_iterator, which adapts a
* preexistent unsafe iterator class.
*/
template<typename Container>
class safe_container;
template<typename Iterator,typename Container>
class safe_iterator:
public detail::iter_adaptor<safe_iterator<Iterator,Container>,Iterator>,
public detail::safe_iterator_base
{
typedef detail::iter_adaptor<safe_iterator,Iterator> super;
typedef detail::safe_iterator_base safe_super;
public:
typedef Container container_type;
typedef typename Iterator::reference reference;
typedef typename Iterator::difference_type difference_type;
safe_iterator(){}
explicit safe_iterator(safe_container<container_type>* cont_):
safe_super(cont_){}
template<typename T0>
safe_iterator(const T0& t0,safe_container<container_type>* cont_):
super(Iterator(t0)),safe_super(cont_){}
template<typename T0,typename T1>
safe_iterator(
const T0& t0,const T1& t1,safe_container<container_type>* cont_):
super(Iterator(t0,t1)),safe_super(cont_){}
safe_iterator& operator=(const safe_iterator& x)
{
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(x);
this->base_reference()=x.base_reference();
safe_super::operator=(x);
return *this;
}
const container_type* owner()const
{
return
static_cast<const container_type*>(
static_cast<const safe_container<container_type>*>(
this->safe_super::owner()));
}
/* get_node is not to be used by the user */
typedef typename Iterator::node_type node_type;
node_type* get_node()const{return this->base_reference().get_node();}
private:
friend class boost::multi_index::detail::iter_adaptor_access;
reference dereference()const
{
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(*this);
BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(*this);
return *(this->base_reference());
}
bool equal(const safe_iterator& x)const
{
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(*this);
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(x);
BOOST_MULTI_INDEX_CHECK_SAME_OWNER(*this,x);
return this->base_reference()==x.base_reference();
}
void increment()
{
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(*this);
BOOST_MULTI_INDEX_CHECK_INCREMENTABLE_ITERATOR(*this);
++(this->base_reference());
}
void decrement()
{
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(*this);
BOOST_MULTI_INDEX_CHECK_DECREMENTABLE_ITERATOR(*this);
--(this->base_reference());
}
void advance(difference_type n)
{
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(*this);
BOOST_MULTI_INDEX_CHECK_IN_BOUNDS(*this,n);
this->base_reference()+=n;
}
difference_type distance_to(const safe_iterator& x)const
{
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(*this);
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(x);
BOOST_MULTI_INDEX_CHECK_SAME_OWNER(*this,x);
return x.base_reference()-this->base_reference();
}
#if !defined(BOOST_MULTI_INDEX_DISABLE_SERIALIZATION)
/* Serialization. Note that Iterator::save and Iterator:load
* are assumed to be defined and public: at first sight it seems
* like we could have resorted to the public serialization interface
* for doing the forwarding to the adapted iterator class:
* ar<<base_reference();
* ar>>base_reference();
* but this would cause incompatibilities if a saving
* program is in safe mode and the loading program is not, or
* viceversa --in safe mode, the archived iterator data is one layer
* deeper, this is especially relevant with XML archives.
* It'd be nice if Boost.Serialization provided some forwarding
* facility for use by adaptor classes.
*/
friend class boost::serialization::access;
BOOST_SERIALIZATION_SPLIT_MEMBER()
template<class Archive>
void save(Archive& ar,const unsigned int version)const
{
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(*this);
this->base_reference().save(ar,version);
}
template<class Archive>
void load(Archive& ar,const unsigned int version)
{
this->base_reference().load(ar,version);
safe_super::uncheck();
}
#endif
};
template<typename Container>
class safe_container:public detail::safe_container_base
{
typedef detail::safe_container_base super;
public:
void detach_dereferenceable_iterators()
{
typedef typename Container::iterator iterator;
iterator end_=static_cast<Container*>(this)->end();
iterator *prev_,*next_;
for(
prev_=static_cast<iterator*>(&this->header);
(next_=static_cast<iterator*>(prev_->next))!=0;){
if(*next_!=end_){
prev_->next=next_->next;
next_->cont=0;
}
else prev_=next_;
}
}
void swap(safe_container<Container>& x)
{
super::swap(x);
}
};
} /* namespace multi_index::safe_mode */
} /* namespace multi_index */
#if !defined(BOOST_MULTI_INDEX_DISABLE_SERIALIZATION)
namespace serialization{
template<typename Iterator,typename Container>
struct version<
boost::multi_index::safe_mode::safe_iterator<Iterator,Container>
>
{
BOOST_STATIC_CONSTANT(
int,value=boost::serialization::version<Iterator>::value);
};
} /* namespace serialization */
#endif
} /* namespace boost */
#endif /* BOOST_MULTI_INDEX_ENABLE_SAFE_MODE */
#endif
@@ -0,0 +1,453 @@
/* Copyright 2003-2013 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_SCOPE_GUARD_HPP
#define BOOST_MULTI_INDEX_DETAIL_SCOPE_GUARD_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/detail/no_exceptions_support.hpp>
#include <boost/mpl/if.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<Programming>: Change the Way You
* Write Exception-Safe Code - Forever", C/C++ Users Jornal, Dec 2000,
* http://www.drdobbs.com/184403758
* with the following modifications:
* - General pretty formatting (pretty to my taste at least.)
* - Naming style changed to standard C++ library requirements.
* - 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.
*
* NB: CodeWarrior Pro 8 seems to have problems looking up safe_execute
* without an explicit qualification.
*
* We also define the following variants of the idiom:
*
* - make_guard_if_c<bool>( ... )
* - make_guard_if<IntegralConstant>( ... )
* - make_obj_guard_if_c<bool>( ... )
* - make_obj_guard_if<IntegralConstant>( ... )
* which may be used with a compile-time constant to yield
* a "null_guard" if the boolean compile-time parameter is false,
* or conversely, the guard is only constructed if the constant is true.
* This is useful to avoid extra tagging, because the returned
* null_guard can be optimzed comlpetely away by the compiler.
*/
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<typename J>
static void safe_execute(J& j){
BOOST_TRY{
if(!j.dismissed_)j.execute();
}
BOOST_CATCH(...){}
BOOST_CATCH_END
}
mutable bool dismissed_;
private:
scope_guard_impl_base& operator=(const scope_guard_impl_base&);
};
typedef const scope_guard_impl_base& scope_guard;
struct null_guard : public scope_guard_impl_base
{
template< class T1 >
null_guard( const T1& )
{ }
template< class T1, class T2 >
null_guard( const T1&, const T2& )
{ }
template< class T1, class T2, class T3 >
null_guard( const T1&, const T2&, const T3& )
{ }
template< class T1, class T2, class T3, class T4 >
null_guard( const T1&, const T2&, const T3&, const T4& )
{ }
template< class T1, class T2, class T3, class T4, class T5 >
null_guard( const T1&, const T2&, const T3&, const T4&, const T5& )
{ }
};
template< bool cond, class T >
struct null_guard_return
{
typedef typename boost::mpl::if_c<cond,T,null_guard>::type type;
};
template<typename F>
class scope_guard_impl0:public scope_guard_impl_base
{
public:
scope_guard_impl0(F fun):fun_(fun){}
~scope_guard_impl0(){scope_guard_impl_base::safe_execute(*this);}
void execute(){fun_();}
protected:
F fun_;
};
template<typename F>
inline scope_guard_impl0<F> make_guard(F fun)
{
return scope_guard_impl0<F>(fun);
}
template<bool cond, typename F>
inline typename null_guard_return<cond,scope_guard_impl0<F> >::type
make_guard_if_c(F fun)
{
return typename null_guard_return<cond,scope_guard_impl0<F> >::type(fun);
}
template<typename C, typename F>
inline typename null_guard_return<C::value,scope_guard_impl0<F> >::type
make_guard_if(F fun)
{
return make_guard_if<C::value>(fun);
}
template<typename F,typename P1>
class scope_guard_impl1:public scope_guard_impl_base
{
public:
scope_guard_impl1(F fun,P1 p1):fun_(fun),p1_(p1){}
~scope_guard_impl1(){scope_guard_impl_base::safe_execute(*this);}
void execute(){fun_(p1_);}
protected:
F fun_;
const P1 p1_;
};
template<typename F,typename P1>
inline scope_guard_impl1<F,P1> make_guard(F fun,P1 p1)
{
return scope_guard_impl1<F,P1>(fun,p1);
}
template<bool cond, typename F,typename P1>
inline typename null_guard_return<cond,scope_guard_impl1<F,P1> >::type
make_guard_if_c(F fun,P1 p1)
{
return typename null_guard_return<cond,scope_guard_impl1<F,P1> >::type(fun,p1);
}
template<typename C, typename F,typename P1>
inline typename null_guard_return<C::value,scope_guard_impl1<F,P1> >::type
make_guard_if(F fun,P1 p1)
{
return make_guard_if_c<C::value>(fun,p1);
}
template<typename F,typename P1,typename P2>
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(){scope_guard_impl_base::safe_execute(*this);}
void execute(){fun_(p1_,p2_);}
protected:
F fun_;
const P1 p1_;
const P2 p2_;
};
template<typename F,typename P1,typename P2>
inline scope_guard_impl2<F,P1,P2> make_guard(F fun,P1 p1,P2 p2)
{
return scope_guard_impl2<F,P1,P2>(fun,p1,p2);
}
template<bool cond, typename F,typename P1,typename P2>
inline typename null_guard_return<cond,scope_guard_impl2<F,P1,P2> >::type
make_guard_if_c(F fun,P1 p1,P2 p2)
{
return typename null_guard_return<cond,scope_guard_impl2<F,P1,P2> >::type(fun,p1,p2);
}
template<typename C, typename F,typename P1,typename P2>
inline typename null_guard_return<C::value,scope_guard_impl2<F,P1,P2> >::type
make_guard_if(F fun,P1 p1,P2 p2)
{
return make_guard_if_c<C::value>(fun,p1,p2);
}
template<typename F,typename P1,typename P2,typename P3>
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(){scope_guard_impl_base::safe_execute(*this);}
void execute(){fun_(p1_,p2_,p3_);}
protected:
F fun_;
const P1 p1_;
const P2 p2_;
const P3 p3_;
};
template<typename F,typename P1,typename P2,typename P3>
inline scope_guard_impl3<F,P1,P2,P3> make_guard(F fun,P1 p1,P2 p2,P3 p3)
{
return scope_guard_impl3<F,P1,P2,P3>(fun,p1,p2,p3);
}
template<bool cond,typename F,typename P1,typename P2,typename P3>
inline typename null_guard_return<cond,scope_guard_impl3<F,P1,P2,P3> >::type
make_guard_if_c(F fun,P1 p1,P2 p2,P3 p3)
{
return typename null_guard_return<cond,scope_guard_impl3<F,P1,P2,P3> >::type(fun,p1,p2,p3);
}
template<typename C,typename F,typename P1,typename P2,typename P3>
inline typename null_guard_return< C::value,scope_guard_impl3<F,P1,P2,P3> >::type
make_guard_if(F fun,P1 p1,P2 p2,P3 p3)
{
return make_guard_if_c<C::value>(fun,p1,p2,p3);
}
template<typename F,typename P1,typename P2,typename P3,typename P4>
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(){scope_guard_impl_base::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<typename F,typename P1,typename P2,typename P3,typename P4>
inline scope_guard_impl4<F,P1,P2,P3,P4> make_guard(
F fun,P1 p1,P2 p2,P3 p3,P4 p4)
{
return scope_guard_impl4<F,P1,P2,P3,P4>(fun,p1,p2,p3,p4);
}
template<bool cond, typename F,typename P1,typename P2,typename P3,typename P4>
inline typename null_guard_return<cond,scope_guard_impl4<F,P1,P2,P3,P4> >::type
make_guard_if_c(
F fun,P1 p1,P2 p2,P3 p3,P4 p4)
{
return typename null_guard_return<cond,scope_guard_impl4<F,P1,P2,P3,P4> >::type(fun,p1,p2,p3,p4);
}
template<typename C, typename F,typename P1,typename P2,typename P3,typename P4>
inline typename null_guard_return<C::value,scope_guard_impl4<F,P1,P2,P3,P4> >::type
make_guard_if(
F fun,P1 p1,P2 p2,P3 p3,P4 p4)
{
return make_guard_if_c<C::value>(fun,p1,p2,p3,p4);
}
template<class Obj,typename MemFun>
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(){scope_guard_impl_base::safe_execute(*this);}
void execute(){(obj_.*mem_fun_)();}
protected:
Obj& obj_;
MemFun mem_fun_;
};
template<class Obj,typename MemFun>
inline obj_scope_guard_impl0<Obj,MemFun> make_obj_guard(Obj& obj,MemFun mem_fun)
{
return obj_scope_guard_impl0<Obj,MemFun>(obj,mem_fun);
}
template<bool cond, class Obj,typename MemFun>
inline typename null_guard_return<cond,obj_scope_guard_impl0<Obj,MemFun> >::type
make_obj_guard_if_c(Obj& obj,MemFun mem_fun)
{
return typename null_guard_return<cond,obj_scope_guard_impl0<Obj,MemFun> >::type(obj,mem_fun);
}
template<typename C, class Obj,typename MemFun>
inline typename null_guard_return<C::value,obj_scope_guard_impl0<Obj,MemFun> >::type
make_obj_guard_if(Obj& obj,MemFun mem_fun)
{
return make_obj_guard_if_c<C::value>(obj,mem_fun);
}
template<class Obj,typename MemFun,typename P1>
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(){scope_guard_impl_base::safe_execute(*this);}
void execute(){(obj_.*mem_fun_)(p1_);}
protected:
Obj& obj_;
MemFun mem_fun_;
const P1 p1_;
};
template<class Obj,typename MemFun,typename P1>
inline obj_scope_guard_impl1<Obj,MemFun,P1> make_obj_guard(
Obj& obj,MemFun mem_fun,P1 p1)
{
return obj_scope_guard_impl1<Obj,MemFun,P1>(obj,mem_fun,p1);
}
template<bool cond, class Obj,typename MemFun,typename P1>
inline typename null_guard_return<cond,obj_scope_guard_impl1<Obj,MemFun,P1> >::type
make_obj_guard_if_c( Obj& obj,MemFun mem_fun,P1 p1)
{
return typename null_guard_return<cond,obj_scope_guard_impl1<Obj,MemFun,P1> >::type(obj,mem_fun,p1);
}
template<typename C, class Obj,typename MemFun,typename P1>
inline typename null_guard_return<C::value,obj_scope_guard_impl1<Obj,MemFun,P1> >::type
make_obj_guard_if( Obj& obj,MemFun mem_fun,P1 p1)
{
return make_obj_guard_if_c<C::value>(obj,mem_fun,p1);
}
template<class Obj,typename MemFun,typename P1,typename P2>
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(){scope_guard_impl_base::safe_execute(*this);}
void execute(){(obj_.*mem_fun_)(p1_,p2_);}
protected:
Obj& obj_;
MemFun mem_fun_;
const P1 p1_;
const P2 p2_;
};
template<class Obj,typename MemFun,typename P1,typename P2>
inline obj_scope_guard_impl2<Obj,MemFun,P1,P2>
make_obj_guard(Obj& obj,MemFun mem_fun,P1 p1,P2 p2)
{
return obj_scope_guard_impl2<Obj,MemFun,P1,P2>(obj,mem_fun,p1,p2);
}
template<bool cond, class Obj,typename MemFun,typename P1,typename P2>
inline typename null_guard_return<cond,obj_scope_guard_impl2<Obj,MemFun,P1,P2> >::type
make_obj_guard_if_c(Obj& obj,MemFun mem_fun,P1 p1,P2 p2)
{
return typename null_guard_return<cond,obj_scope_guard_impl2<Obj,MemFun,P1,P2> >::type(obj,mem_fun,p1,p2);
}
template<typename C, class Obj,typename MemFun,typename P1,typename P2>
inline typename null_guard_return<C::value,obj_scope_guard_impl2<Obj,MemFun,P1,P2> >::type
make_obj_guard_if(Obj& obj,MemFun mem_fun,P1 p1,P2 p2)
{
return make_obj_guard_if_c<C::value>(obj,mem_fun,p1,p2);
}
template<class Obj,typename MemFun,typename P1,typename P2,typename P3>
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(){scope_guard_impl_base::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<class Obj,typename MemFun,typename P1,typename P2,typename P3>
inline obj_scope_guard_impl3<Obj,MemFun,P1,P2,P3>
make_obj_guard(Obj& obj,MemFun mem_fun,P1 p1,P2 p2,P3 p3)
{
return obj_scope_guard_impl3<Obj,MemFun,P1,P2,P3>(obj,mem_fun,p1,p2,p3);
}
template<bool cond, class Obj,typename MemFun,typename P1,typename P2,typename P3>
inline typename null_guard_return<cond,obj_scope_guard_impl3<Obj,MemFun,P1,P2,P3> >::type
make_obj_guard_if_c(Obj& obj,MemFun mem_fun,P1 p1,P2 p2,P3 p3)
{
return typename null_guard_return<cond,obj_scope_guard_impl3<Obj,MemFun,P1,P2,P3> >::type(obj,mem_fun,p1,p2,p3);
}
template<typename C, class Obj,typename MemFun,typename P1,typename P2,typename P3>
inline typename null_guard_return<C::value,obj_scope_guard_impl3<Obj,MemFun,P1,P2,P3> >::type
make_obj_guard_if(Obj& obj,MemFun mem_fun,P1 p1,P2 p2,P3 p3)
{
return make_obj_guard_if_c<C::value>(obj,mem_fun,p1,p2,p3);
}
} /* namespace multi_index::detail */
} /* namespace multi_index */
} /* namespace boost */
#endif
@@ -0,0 +1,217 @@
/* Copyright 2003-2015 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_SEQ_INDEX_NODE_HPP
#define BOOST_MULTI_INDEX_DETAIL_SEQ_INDEX_NODE_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <algorithm>
#include <boost/detail/allocator_utilities.hpp>
#include <boost/multi_index/detail/raw_ptr.hpp>
namespace boost{
namespace multi_index{
namespace detail{
/* doubly-linked node for use by sequenced_index */
template<typename Allocator>
struct sequenced_index_node_impl
{
typedef typename
boost::detail::allocator::rebind_to<
Allocator,sequenced_index_node_impl
>::type::pointer pointer;
typedef typename
boost::detail::allocator::rebind_to<
Allocator,sequenced_index_node_impl
>::type::const_pointer const_pointer;
pointer& prior(){return prior_;}
pointer prior()const{return prior_;}
pointer& next(){return next_;}
pointer next()const{return next_;}
/* interoperability with bidir_node_iterator */
static void increment(pointer& x){x=x->next();}
static void decrement(pointer& x){x=x->prior();}
/* algorithmic stuff */
static void link(pointer x,pointer header)
{
x->prior()=header->prior();
x->next()=header;
x->prior()->next()=x->next()->prior()=x;
};
static void unlink(pointer x)
{
x->prior()->next()=x->next();
x->next()->prior()=x->prior();
}
static void relink(pointer position,pointer x)
{
unlink(x);
x->prior()=position->prior();
x->next()=position;
x->prior()->next()=x->next()->prior()=x;
}
static void relink(pointer position,pointer x,pointer y)
{
/* position is assumed not to be in [x,y) */
if(x!=y){
pointer 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(pointer header)
{
pointer x=header;
do{
pointer y=x->next();
std::swap(x->prior(),x->next());
x=y;
}while(x!=header);
}
static void swap(pointer x,pointer 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:
pointer prior_;
pointer next_;
};
template<typename Super>
struct sequenced_index_node_trampoline:
sequenced_index_node_impl<
typename boost::detail::allocator::rebind_to<
typename Super::allocator_type,
char
>::type
>
{
typedef sequenced_index_node_impl<
typename boost::detail::allocator::rebind_to<
typename Super::allocator_type,
char
>::type
> impl_type;
};
template<typename Super>
struct sequenced_index_node:Super,sequenced_index_node_trampoline<Super>
{
private:
typedef sequenced_index_node_trampoline<Super> trampoline;
public:
typedef typename trampoline::impl_type impl_type;
typedef typename trampoline::pointer impl_pointer;
typedef typename trampoline::const_pointer const_impl_pointer;
impl_pointer& prior(){return trampoline::prior();}
impl_pointer prior()const{return trampoline::prior();}
impl_pointer& next(){return trampoline::next();}
impl_pointer next()const{return trampoline::next();}
impl_pointer impl()
{
return static_cast<impl_pointer>(
static_cast<impl_type*>(static_cast<trampoline*>(this)));
}
const_impl_pointer impl()const
{
return static_cast<const_impl_pointer>(
static_cast<const impl_type*>(static_cast<const trampoline*>(this)));
}
static sequenced_index_node* from_impl(impl_pointer x)
{
return
static_cast<sequenced_index_node*>(
static_cast<trampoline*>(
raw_ptr<impl_type*>(x)));
}
static const sequenced_index_node* from_impl(const_impl_pointer x)
{
return
static_cast<const sequenced_index_node*>(
static_cast<const trampoline*>(
raw_ptr<const impl_type*>(x)));
}
/* interoperability with bidir_node_iterator */
static void increment(sequenced_index_node*& x)
{
impl_pointer xi=x->impl();
trampoline::increment(xi);
x=from_impl(xi);
}
static void decrement(sequenced_index_node*& x)
{
impl_pointer xi=x->impl();
trampoline::decrement(xi);
x=from_impl(xi);
}
};
} /* namespace multi_index::detail */
} /* namespace multi_index */
} /* namespace boost */
#endif
@@ -0,0 +1,203 @@
/* Copyright 2003-2016 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_SEQ_INDEX_OPS_HPP
#define BOOST_MULTI_INDEX_DETAIL_SEQ_INDEX_OPS_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <boost/detail/no_exceptions_support.hpp>
#include <boost/multi_index/detail/seq_index_node.hpp>
#include <boost/limits.hpp>
#include <boost/type_traits/aligned_storage.hpp>
#include <boost/type_traits/alignment_of.hpp>
#include <cstddef>
namespace boost{
namespace multi_index{
namespace detail{
/* Common code for sequenced_index memfuns having templatized and
* non-templatized versions.
*/
template <typename SequencedIndex,typename Predicate>
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 <typename SequencedIndex,class BinaryPredicate>
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 <typename SequencedIndex,typename Compare>
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<typename Node,typename Compare>
void sequenced_index_collate(
BOOST_DEDUCED_TYPENAME Node::impl_type* x,
BOOST_DEDUCED_TYPENAME Node::impl_type* y,
Compare comp)
{
typedef typename Node::impl_type impl_type;
typedef typename Node::impl_pointer impl_pointer;
impl_pointer first0=x->next();
impl_pointer last0=x;
impl_pointer first1=y->next();
impl_pointer last1=y;
while(first0!=last0&&first1!=last1){
if(comp(
Node::from_impl(first1)->value(),Node::from_impl(first0)->value())){
impl_pointer tmp=first1->next();
impl_type::relink(first0,first1);
first1=tmp;
}
else first0=first0->next();
}
impl_type::relink(last0,first1,last1);
}
/* Some versions of CGG require a bogus typename in counter_spc
* inside sequenced_index_sort if the following is defined
* also inside sequenced_index_sort.
*/
BOOST_STATIC_CONSTANT(
std::size_t,
sequenced_index_sort_max_fill=
(std::size_t)std::numeric_limits<std::size_t>::digits+1);
#include <boost/multi_index/detail/ignore_wstrict_aliasing.hpp>
template<typename Node,typename Compare>
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;
typedef typename Node::impl_type impl_type;
typedef typename Node::impl_pointer impl_pointer;
typedef typename aligned_storage<
sizeof(impl_type),
alignment_of<impl_type>::value
>::type carry_spc_type;
carry_spc_type carry_spc;
impl_type& carry=
*reinterpret_cast<impl_type*>(&carry_spc);
typedef typename aligned_storage<
sizeof(
impl_type
[sequenced_index_sort_max_fill]),
alignment_of<
impl_type
[sequenced_index_sort_max_fill]
>::value
>::type counter_spc_type;
counter_spc_type counter_spc;
impl_type* counter=
reinterpret_cast<impl_type*>(&counter_spc);
std::size_t fill=0;
carry.prior()=carry.next()=static_cast<impl_pointer>(&carry);
counter[0].prior()=counter[0].next()=static_cast<impl_pointer>(&counter[0]);
BOOST_TRY{
while(header->next()!=header->impl()){
impl_type::relink(carry.next(),header->next());
std::size_t i=0;
while(i<fill&&counter[i].next()!=static_cast<impl_pointer>(&counter[i])){
sequenced_index_collate<Node>(&carry,&counter[i++],comp);
}
impl_type::swap(
static_cast<impl_pointer>(&carry),
static_cast<impl_pointer>(&counter[i]));
if(i==fill){
++fill;
counter[fill].prior()=counter[fill].next()=
static_cast<impl_pointer>(&counter[fill]);
}
}
for(std::size_t i=1;i<fill;++i){
sequenced_index_collate<Node>(&counter[i],&counter[i-1],comp);
}
impl_type::swap(
header->impl(),static_cast<impl_pointer>(&counter[fill-1]));
}
BOOST_CATCH(...)
{
impl_type::relink(
header->impl(),carry.next(),static_cast<impl_pointer>(&carry));
for(std::size_t i=0;i<=fill;++i){
impl_type::relink(
header->impl(),counter[i].next(),
static_cast<impl_pointer>(&counter[i]));
}
BOOST_RETHROW;
}
BOOST_CATCH_END
}
#include <boost/multi_index/detail/restore_wstrict_aliasing.hpp>
} /* namespace multi_index::detail */
} /* namespace multi_index */
} /* namespace boost */
#endif
@@ -0,0 +1,73 @@
/* Copyright 2003-2013 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_SERIALIZATION_VERSION_HPP
#define BOOST_MULTI_INDEX_DETAIL_SERIALIZATION_VERSION_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <boost/serialization/split_member.hpp>
#include <boost/serialization/version.hpp>
namespace boost{
namespace multi_index{
namespace detail{
/* Helper class for storing and retrieving a given type serialization class
* version while avoiding saving the number multiple times in the same
* archive.
* Behavior undefined if template partial specialization is not supported.
*/
template<typename T>
struct serialization_version
{
serialization_version():
value(boost::serialization::version<serialization_version>::value){}
serialization_version& operator=(unsigned int x){value=x;return *this;};
operator unsigned int()const{return value;}
private:
friend class boost::serialization::access;
BOOST_SERIALIZATION_SPLIT_MEMBER()
template<class Archive>
void save(Archive&,const unsigned int)const{}
template<class Archive>
void load(Archive&,const unsigned int version)
{
this->value=version;
}
unsigned int value;
};
} /* namespace multi_index::detail */
} /* namespace multi_index */
namespace serialization {
template<typename T>
struct version<boost::multi_index::detail::serialization_version<T> >
{
BOOST_STATIC_CONSTANT(int,value=version<T>::value);
};
} /* namespace serialization */
} /* namespace boost */
#endif
@@ -0,0 +1,76 @@
/* Copyright 2003-2013 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_UINTPTR_TYPE_HPP
#define BOOST_MULTI_INDEX_DETAIL_UINTPTR_TYPE_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <boost/mpl/bool.hpp>
namespace boost{
namespace multi_index{
namespace detail{
/* has_uintptr_type is an MPL integral constant determining whether
* there exists an unsigned integral type with the same size as
* void *.
* uintptr_type is such a type if has_uintptr is true, or unsigned int
* otherwise.
* Note that uintptr_type is more restrictive than C99 uintptr_t,
* where an integral type with size greater than that of void *
* would be conformant.
*/
template<int N>struct uintptr_candidates;
template<>struct uintptr_candidates<-1>{typedef unsigned int type;};
template<>struct uintptr_candidates<0> {typedef unsigned int type;};
template<>struct uintptr_candidates<1> {typedef unsigned short type;};
template<>struct uintptr_candidates<2> {typedef unsigned long type;};
#if defined(BOOST_HAS_LONG_LONG)
template<>struct uintptr_candidates<3> {typedef boost::ulong_long_type type;};
#else
template<>struct uintptr_candidates<3> {typedef unsigned int type;};
#endif
#if defined(BOOST_HAS_MS_INT64)
template<>struct uintptr_candidates<4> {typedef unsigned __int64 type;};
#else
template<>struct uintptr_candidates<4> {typedef unsigned int type;};
#endif
struct uintptr_aux
{
BOOST_STATIC_CONSTANT(int,index=
sizeof(void*)==sizeof(uintptr_candidates<0>::type)?0:
sizeof(void*)==sizeof(uintptr_candidates<1>::type)?1:
sizeof(void*)==sizeof(uintptr_candidates<2>::type)?2:
sizeof(void*)==sizeof(uintptr_candidates<3>::type)?3:
sizeof(void*)==sizeof(uintptr_candidates<4>::type)?4:-1);
BOOST_STATIC_CONSTANT(bool,has_uintptr_type=(index>=0));
typedef uintptr_candidates<index>::type type;
};
typedef mpl::bool_<uintptr_aux::has_uintptr_type> has_uintptr_type;
typedef uintptr_aux::type uintptr_type;
} /* namespace multi_index::detail */
} /* namespace multi_index */
} /* namespace boost */
#endif
@@ -0,0 +1,66 @@
/* Copyright 2003-2013 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_UNBOUNDED_HPP
#define BOOST_MULTI_INDEX_DETAIL_UNBOUNDED_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <boost/detail/workaround.hpp>
namespace boost{
namespace multi_index{
/* dummy type and variable for use in ordered_index::range() */
/* ODR-abiding technique shown at the example attached to
* http://lists.boost.org/Archives/boost/2006/07/108355.php
*/
namespace detail{class unbounded_helper;}
detail::unbounded_helper unbounded(detail::unbounded_helper);
namespace detail{
class unbounded_helper
{
unbounded_helper(){}
unbounded_helper(const unbounded_helper&){}
friend unbounded_helper multi_index::unbounded(unbounded_helper);
};
typedef unbounded_helper (*unbounded_type)(unbounded_helper);
} /* namespace multi_index::detail */
inline detail::unbounded_helper unbounded(detail::unbounded_helper)
{
return detail::unbounded_helper();
}
/* tags used in the implementation of range */
namespace detail{
struct none_unbounded_tag{};
struct lower_unbounded_tag{};
struct upper_unbounded_tag{};
struct both_unbounded_tag{};
} /* namespace multi_index::detail */
} /* namespace multi_index */
} /* namespace boost */
#endif
@@ -0,0 +1,56 @@
/* Copyright 2003-2015 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_VALUE_COMPARE_HPP
#define BOOST_MULTI_INDEX_DETAIL_VALUE_COMPARE_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <boost/call_traits.hpp>
namespace boost{
namespace multi_index{
namespace detail{
template<typename Value,typename KeyFromValue,typename Compare>
struct value_comparison
{
typedef Value first_argument_type;
typedef Value second_argument_type;
typedef bool result_type;
value_comparison(
const KeyFromValue& key_=KeyFromValue(),const Compare& comp_=Compare()):
key(key_),comp(comp_)
{
}
bool operator()(
typename call_traits<Value>::param_type x,
typename call_traits<Value>::param_type y)const
{
return comp(key(x),key(y));
}
private:
KeyFromValue key;
Compare comp;
};
} /* namespace multi_index::detail */
} /* namespace multi_index */
} /* namespace boost */
#endif
@@ -0,0 +1,247 @@
/* Copyright 2003-2013 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_VARTEMPL_SUPPORT_HPP
#define BOOST_MULTI_INDEX_DETAIL_VARTEMPL_SUPPORT_HPP
#if defined(_MSC_VER)
#pragma once
#endif
/* Utilities for emulation of variadic template functions. Variadic packs are
* replaced by lists of BOOST_MULTI_INDEX_LIMIT_VARTEMPL_ARGS parameters:
*
* - typename... Args --> BOOST_MULTI_INDEX_TEMPLATE_PARAM_PACK
* - Args&&... args --> BOOST_MULTI_INDEX_FUNCTION_PARAM_PACK
* - std::forward<Args>(args)... --> BOOST_MULTI_INDEX_FORWARD_PARAM_PACK
*
* Forwarding emulated with Boost.Move. A template functions foo_imp
* defined in such way accepts *exactly* BOOST_MULTI_INDEX_LIMIT_VARTEMPL_ARGS
* arguments: variable number of arguments is emulated by providing a set of
* overloads foo forwarding to foo_impl with
*
* BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL
* BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL_EXTRA_ARG (initial extra arg)
*
* which fill the extra args with boost::multi_index::detail::noarg's.
* boost::multi_index::detail::vartempl_placement_new works the opposite
* way: it acceps a full a pointer x to Value and a
* BOOST_MULTI_INDEX_FUNCTION_PARAM_PACK and forwards to
* new(x) Value(args) where args is the argument pack after discarding
* noarg's.
*
* Emulation decays to the real thing when the compiler supports variadic
* templates and move semantics natively.
*/
#include <boost/config.hpp>
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)||\
defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
#include <boost/move/core.hpp>
#include <boost/move/utility.hpp>
#include <boost/preprocessor/arithmetic/add.hpp>
#include <boost/preprocessor/arithmetic/sub.hpp>
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/control/if.hpp>
#include <boost/preprocessor/facilities/empty.hpp>
#include <boost/preprocessor/facilities/intercept.hpp>
#include <boost/preprocessor/logical/and.hpp>
#include <boost/preprocessor/punctuation/comma.hpp>
#include <boost/preprocessor/punctuation/comma_if.hpp>
#include <boost/preprocessor/repetition/enum.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
#include <boost/preprocessor/seq/elem.hpp>
#if !defined(BOOST_MULTI_INDEX_LIMIT_VARTEMPL_ARGS)
#define BOOST_MULTI_INDEX_LIMIT_VARTEMPL_ARGS 5
#endif
#define BOOST_MULTI_INDEX_TEMPLATE_PARAM_PACK \
BOOST_PP_ENUM_PARAMS( \
BOOST_MULTI_INDEX_LIMIT_VARTEMPL_ARGS,typename T)
#define BOOST_MULTI_INDEX_VARTEMPL_ARG(z,n,_) \
BOOST_FWD_REF(BOOST_PP_CAT(T,n)) BOOST_PP_CAT(t,n)
#define BOOST_MULTI_INDEX_FUNCTION_PARAM_PACK \
BOOST_PP_ENUM( \
BOOST_MULTI_INDEX_LIMIT_VARTEMPL_ARGS, \
BOOST_MULTI_INDEX_VARTEMPL_ARG,~)
#define BOOST_MULTI_INDEX_VARTEMPL_FORWARD_ARG(z,n,_) \
boost::forward<BOOST_PP_CAT(T,n)>(BOOST_PP_CAT(t,n))
#define BOOST_MULTI_INDEX_FORWARD_PARAM_PACK \
BOOST_PP_ENUM( \
BOOST_MULTI_INDEX_LIMIT_VARTEMPL_ARGS, \
BOOST_MULTI_INDEX_VARTEMPL_FORWARD_ARG,~)
namespace boost{namespace multi_index{namespace detail{
struct noarg{};
}}}
/* call vartempl function without args */
#define BOOST_MULTI_INDEX_NULL_PARAM_PACK \
BOOST_PP_ENUM_PARAMS( \
BOOST_MULTI_INDEX_LIMIT_VARTEMPL_ARGS, \
boost::multi_index::detail::noarg() BOOST_PP_INTERCEPT)
#define BOOST_MULTI_INDEX_TEMPLATE_N(n) \
template<BOOST_PP_ENUM_PARAMS(n,typename T)>
#define BOOST_MULTI_INDEX_TEMPLATE_0(n)
#define BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL_AUX(z,n,data) \
BOOST_PP_IF(n, \
BOOST_MULTI_INDEX_TEMPLATE_N, \
BOOST_MULTI_INDEX_TEMPLATE_0)(n) \
BOOST_PP_SEQ_ELEM(0,data) /* ret */ \
BOOST_PP_SEQ_ELEM(1,data) /* name_from */ ( \
BOOST_PP_ENUM(n,BOOST_MULTI_INDEX_VARTEMPL_ARG,~)) \
{ \
return BOOST_PP_SEQ_ELEM(2,data) /* name_to */ ( \
BOOST_PP_ENUM(n,BOOST_MULTI_INDEX_VARTEMPL_FORWARD_ARG,~) \
BOOST_PP_COMMA_IF( \
BOOST_PP_AND( \
n,BOOST_PP_SUB(BOOST_MULTI_INDEX_LIMIT_VARTEMPL_ARGS,n))) \
BOOST_PP_ENUM_PARAMS( \
BOOST_PP_SUB(BOOST_MULTI_INDEX_LIMIT_VARTEMPL_ARGS,n), \
boost::multi_index::detail::noarg() BOOST_PP_INTERCEPT) \
); \
}
#define BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL( \
ret,name_from,name_to) \
BOOST_PP_REPEAT_FROM_TO( \
0,BOOST_PP_ADD(BOOST_MULTI_INDEX_LIMIT_VARTEMPL_ARGS,1), \
BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL_AUX, \
(ret)(name_from)(name_to))
#define BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL_EXTRA_ARG_AUX( \
z,n,data) \
BOOST_PP_IF(n, \
BOOST_MULTI_INDEX_TEMPLATE_N, \
BOOST_MULTI_INDEX_TEMPLATE_0)(n) \
BOOST_PP_SEQ_ELEM(0,data) /* ret */ \
BOOST_PP_SEQ_ELEM(1,data) /* name_from */ ( \
BOOST_PP_SEQ_ELEM(3,data) BOOST_PP_SEQ_ELEM(4,data) /* extra arg */\
BOOST_PP_COMMA_IF(n) \
BOOST_PP_ENUM(n,BOOST_MULTI_INDEX_VARTEMPL_ARG,~)) \
{ \
return BOOST_PP_SEQ_ELEM(2,data) /* name_to */ ( \
BOOST_PP_SEQ_ELEM(4,data) /* extra_arg_name */ \
BOOST_PP_COMMA_IF(n) \
BOOST_PP_ENUM(n,BOOST_MULTI_INDEX_VARTEMPL_FORWARD_ARG,~) \
BOOST_PP_COMMA_IF( \
BOOST_PP_SUB(BOOST_MULTI_INDEX_LIMIT_VARTEMPL_ARGS,n)) \
BOOST_PP_ENUM_PARAMS( \
BOOST_PP_SUB(BOOST_MULTI_INDEX_LIMIT_VARTEMPL_ARGS,n), \
boost::multi_index::detail::noarg() BOOST_PP_INTERCEPT) \
); \
}
#define BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL_EXTRA_ARG( \
ret,name_from,name_to,extra_arg_type,extra_arg_name) \
BOOST_PP_REPEAT_FROM_TO( \
0,BOOST_PP_ADD(BOOST_MULTI_INDEX_LIMIT_VARTEMPL_ARGS,1), \
BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL_EXTRA_ARG_AUX, \
(ret)(name_from)(name_to)(extra_arg_type)(extra_arg_name))
namespace boost{
namespace multi_index{
namespace detail{
#define BOOST_MULTI_INDEX_VARTEMPL_TO_PLACEMENT_NEW_AUX(z,n,name) \
template< \
typename Value \
BOOST_PP_COMMA_IF(n) \
BOOST_PP_ENUM_PARAMS(n,typename T) \
> \
Value* name( \
Value* x \
BOOST_PP_COMMA_IF(n) \
BOOST_PP_ENUM(n,BOOST_MULTI_INDEX_VARTEMPL_ARG,~) \
BOOST_PP_COMMA_IF( \
BOOST_PP_SUB(BOOST_MULTI_INDEX_LIMIT_VARTEMPL_ARGS,n)) \
BOOST_PP_ENUM_PARAMS( \
BOOST_PP_SUB(BOOST_MULTI_INDEX_LIMIT_VARTEMPL_ARGS,n), \
BOOST_FWD_REF(noarg) BOOST_PP_INTERCEPT)) \
{ \
return new(x) Value( \
BOOST_PP_ENUM(n,BOOST_MULTI_INDEX_VARTEMPL_FORWARD_ARG,~)); \
}
#define BOOST_MULTI_INDEX_VARTEMPL_TO_PLACEMENT_NEW(name) \
BOOST_PP_REPEAT_FROM_TO( \
0,BOOST_PP_ADD(BOOST_MULTI_INDEX_LIMIT_VARTEMPL_ARGS,1), \
BOOST_MULTI_INDEX_VARTEMPL_TO_PLACEMENT_NEW_AUX, \
name)
BOOST_MULTI_INDEX_VARTEMPL_TO_PLACEMENT_NEW(vartempl_placement_new)
#undef BOOST_MULTI_INDEX_VARTEMPL_TO_PLACEMENT_NEW_AUX
#undef BOOST_MULTI_INDEX_VARTEMPL_TO_PLACEMENT_NEW
} /* namespace multi_index::detail */
} /* namespace multi_index */
} /* namespace boost */
#else
/* native variadic templates support */
#include <utility>
#define BOOST_MULTI_INDEX_TEMPLATE_PARAM_PACK typename... Args
#define BOOST_MULTI_INDEX_FUNCTION_PARAM_PACK Args&&... args
#define BOOST_MULTI_INDEX_FORWARD_PARAM_PACK std::forward<Args>(args)...
#define BOOST_MULTI_INDEX_NULL_PARAM_PACK
#define BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL( \
ret,name_from,name_to) \
template<typename... Args> ret name_from(Args&&... args) \
{ \
return name_to(std::forward<Args>(args)...); \
}
#define BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL_EXTRA_ARG( \
ret,name_from,name_to,extra_arg_type,extra_arg_name) \
template<typename... Args> ret name_from( \
extra_arg_type extra_arg_name,Args&&... args) \
{ \
return name_to(extra_arg_name,std::forward<Args>(args)...); \
}
namespace boost{
namespace multi_index{
namespace detail{
template<typename Value,typename... Args>
Value* vartempl_placement_new(Value*x,Args&&... args)
{
return new(x) Value(std::forward<Args>(args)...);
}
} /* namespace multi_index::detail */
} /* namespace multi_index */
} /* namespace boost */
#endif
#endif