stabilize build system: depends, installer, boost/bdb fixes, cross targets groundwork
This commit is contained in:
@@ -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
|
||||
+34
@@ -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
|
||||
+18
@@ -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
|
||||
+11
@@ -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
|
||||
+73
@@ -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
|
||||
Reference in New Issue
Block a user