Initial Commit
This commit is contained in:
@@ -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
|
||||
Reference in New Issue
Block a user