Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:42:07

0001 /* Copyright 2003-2020 Joaquin M Lopez Munoz.
0002  * Distributed under the Boost Software License, Version 1.0.
0003  * (See accompanying file LICENSE_1_0.txt or copy at
0004  * http://www.boost.org/LICENSE_1_0.txt)
0005  *
0006  * See http://www.boost.org/libs/multi_index for library home page.
0007  */
0008 
0009 #ifndef BOOST_MULTI_INDEX_DETAIL_HASH_INDEX_NODE_HPP
0010 #define BOOST_MULTI_INDEX_DETAIL_HASH_INDEX_NODE_HPP
0011 
0012 #if defined(_MSC_VER)
0013 #pragma once
0014 #endif
0015 
0016 #include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
0017 #include <boost/multi_index/detail/allocator_traits.hpp>
0018 #include <boost/multi_index/detail/raw_ptr.hpp>
0019 #include <utility>
0020 
0021 namespace boost{
0022 
0023 namespace multi_index{
0024 
0025 namespace detail{
0026 
0027 /* Certain C++ requirements on unordered associative containers (see LWG issue
0028  * #579) imply a data structure where nodes are linked in a single list, which
0029  * in its turn forces implementors to add additional overhed per node to
0030  * associate each with its corresponding bucket. Others resort to storing hash
0031  * values, we use an alternative structure providing unconditional O(1)
0032  * manipulation, even in situations of unfair hash distribution, plus some
0033  * lookup speedups. For unique indices we maintain a doubly linked list of
0034  * nodes except that if N is the first node of a bucket its associated
0035  * bucket node is embedded between N and the preceding node in the following
0036  * manner:
0037  *
0038  *        +---+   +---+       +---+   +---+
0039  *     <--+   |<--+   |    <--+   |<--+   |
0040  *   ...  | B0|   | B1|  ...  | B1|   | B2|  ...
0041  *        |   |-+ |   +-->    |   |-+ |   +-->
0042  *        +-+-+ | +---+       +-+-+ | +---+
0043  *              |   ^               |   ^
0044  *              |   |               |   |
0045  *              | +-+               | +-+
0046  *              | |                 | |
0047  *              v |                 v |  
0048  *       --+---+---+---+--   --+---+---+---+--
0049  *     ... |   | B1|   |  ...  |   | B2|   | ...
0050  *       --+---+---+---+--   --+---+---+---+--
0051  *
0052  *
0053  * The fist and last nodes of buckets can be checked with
0054  *
0055  *   first node of a bucket: Npn != N
0056  *   last node of a bucket:  Nnp != N
0057  *
0058  * (n and p short for ->next(), ->prior(), bucket nodes have prior pointers
0059  * only). Pure insert and erase (without lookup) can be unconditionally done
0060  * in O(1).
0061  * For non-unique indices we add the following additional complexity: when
0062  * there is a group of 3 or more equivalent elements, they are linked as
0063  * follows:
0064  *
0065  *         +-----------------------+
0066  *         |                       v
0067  *   +---+ | +---+       +---+   +---+
0068  *   |   | +-+   |       |   |<--+   |
0069  *   | F |   | S |  ...  | P |   | L |
0070  *   |   +-->|   |       |   +-+ |   |
0071  *   +---+   +---+       +---+ | +---+
0072  *     ^                       |
0073  *     +-----------------------+
0074  * 
0075  * F, S, P and L are the first, second, penultimate and last node in the
0076  * group, respectively (S and P can coincide if the group has size 3.) This
0077  * arrangement is used to skip equivalent elements in O(1) when doing lookup,
0078  * while preserving O(1) insert/erase. The following invariants identify
0079  * special positions (some of the operations have to be carefully implemented
0080  * as Xnn is not valid if Xn points to a bucket):
0081  *
0082  *   first node of a bucket: Npnp  == N
0083  *   last node of a bucket:  Nnpp  == N
0084  *   first node of a group:  Nnp != N && Nnppn == N
0085  *   second node of a group: Npn != N && Nppnn == N
0086  *   n-1 node of a group:    Nnp != N && Nnnpp == N
0087  *   last node of a group:   Npn != N && Npnnp == N
0088  * 
0089  * The memory overhead is one pointer per bucket plus two pointers per node,
0090  * probably unbeatable. The resulting structure is bidirectonally traversable,
0091  * though currently we are just providing forward iteration.
0092  */
0093 
0094 template<typename Allocator>
0095 struct hashed_index_node_impl;
0096 
0097 /* half-header (only prior() pointer) to use for the bucket array */
0098 
0099 template<typename Allocator>
0100 struct hashed_index_base_node_impl
0101 {
0102   typedef typename rebind_alloc_for<
0103     Allocator,hashed_index_base_node_impl
0104   >::type                                             base_allocator;
0105   typedef typename rebind_alloc_for<
0106     Allocator,hashed_index_node_impl<Allocator>
0107   >::type                                             node_allocator;
0108   typedef allocator_traits<base_allocator>            base_alloc_traits;
0109   typedef allocator_traits<node_allocator>            node_alloc_traits;
0110   typedef typename base_alloc_traits::pointer         base_pointer;
0111   typedef typename base_alloc_traits::const_pointer   const_base_pointer;
0112   typedef typename node_alloc_traits::pointer         pointer;
0113   typedef typename node_alloc_traits::const_pointer   const_pointer;
0114   typedef typename node_alloc_traits::difference_type difference_type;
0115 
0116   pointer& prior(){return prior_;}
0117   pointer  prior()const{return prior_;}
0118 
0119 private:
0120   pointer prior_;
0121 };
0122 
0123 /* full header (prior() and next()) for the nodes */
0124 
0125 template<typename Allocator>
0126 struct hashed_index_node_impl:hashed_index_base_node_impl<Allocator>
0127 {
0128 private:
0129   typedef hashed_index_base_node_impl<Allocator> super;
0130 
0131 public:  
0132   typedef typename super::base_pointer           base_pointer;
0133   typedef typename super::const_base_pointer     const_base_pointer;
0134   typedef typename super::pointer                pointer;
0135   typedef typename super::const_pointer          const_pointer;
0136 
0137   base_pointer& next(){return next_;}
0138   base_pointer  next()const{return next_;}
0139 
0140   static pointer pointer_from(base_pointer x)
0141   {
0142     return static_cast<pointer>(
0143       static_cast<hashed_index_node_impl*>(
0144         raw_ptr<super*>(x)));
0145   }
0146 
0147   static base_pointer base_pointer_from(pointer x)
0148   {
0149     return static_cast<base_pointer>(
0150       raw_ptr<hashed_index_node_impl*>(x));
0151   }
0152 
0153 private:
0154   base_pointer next_;
0155 };
0156 
0157 /* Boost.MultiIndex requires machinery to reverse unlink operations. A simple
0158  * way to make a pointer-manipulation function undoable is to templatize
0159  * its internal pointer assignments with a functor that, besides doing the
0160  * assignment, keeps track of the original pointer values and can later undo
0161  * the operations in reverse order.
0162  */
0163 
0164 struct default_assigner
0165 {
0166   template<typename T> void operator()(T& x,const T& val){x=val;}
0167 };
0168 
0169 template<typename Node>
0170 struct unlink_undo_assigner
0171 {
0172   typedef typename Node::base_pointer base_pointer;
0173   typedef typename Node::pointer      pointer;
0174 
0175   unlink_undo_assigner():pointer_track_count(0),base_pointer_track_count(0){}
0176 
0177   void operator()(pointer& x,pointer val)
0178   {
0179     pointer_tracks[pointer_track_count].x=&x;
0180     pointer_tracks[pointer_track_count++].val=x;
0181     x=val;
0182   }
0183 
0184   void operator()(base_pointer& x,base_pointer val)
0185   {
0186     base_pointer_tracks[base_pointer_track_count].x=&x;
0187     base_pointer_tracks[base_pointer_track_count++].val=x;
0188     x=val;
0189   }
0190 
0191   void operator()() /* undo op */
0192   {
0193     /* in the absence of aliasing, restitution order is immaterial */
0194 
0195     while(pointer_track_count--){
0196       *(pointer_tracks[pointer_track_count].x)=
0197         pointer_tracks[pointer_track_count].val;
0198     }
0199     while(base_pointer_track_count--){
0200       *(base_pointer_tracks[base_pointer_track_count].x)=
0201         base_pointer_tracks[base_pointer_track_count].val;
0202     }
0203   }
0204 
0205   struct pointer_track     {pointer*      x; pointer      val;};
0206   struct base_pointer_track{base_pointer* x; base_pointer val;};
0207 
0208   /* We know the maximum number of pointer and base pointer assignments that
0209    * the two unlink versions do, so we can statically reserve the needed
0210    * storage.
0211    */
0212 
0213   pointer_track      pointer_tracks[3];
0214   int                pointer_track_count;
0215   base_pointer_track base_pointer_tracks[2];
0216   int                base_pointer_track_count;
0217 };
0218 
0219 /* algorithmic stuff for unique and non-unique variants */
0220 
0221 struct hashed_unique_tag{};
0222 struct hashed_non_unique_tag{};
0223 
0224 template<typename Node,typename Category>
0225 struct hashed_index_node_alg;
0226 
0227 template<typename Node>
0228 struct hashed_index_node_alg<Node,hashed_unique_tag>
0229 {
0230   typedef typename Node::base_pointer       base_pointer;
0231   typedef typename Node::const_base_pointer const_base_pointer;
0232   typedef typename Node::pointer            pointer;
0233   typedef typename Node::const_pointer      const_pointer;
0234 
0235   static bool is_first_of_bucket(pointer x)
0236   {
0237     return x->prior()->next()!=base_pointer_from(x);
0238   }
0239 
0240   static pointer after(pointer x)
0241   {
0242     return is_last_of_bucket(x)?x->next()->prior():pointer_from(x->next());
0243   }
0244 
0245   static pointer after_local(pointer x)
0246   {
0247     return is_last_of_bucket(x)?pointer(0):pointer_from(x->next());
0248   }
0249 
0250   static pointer next_to_inspect(pointer x)
0251   {
0252     return is_last_of_bucket(x)?pointer(0):pointer_from(x->next());
0253   }
0254 
0255   static void link(pointer x,base_pointer buc,pointer end)
0256   {
0257     if(buc->prior()==pointer(0)){ /* empty bucket */
0258       x->prior()=end->prior();
0259       x->next()=end->prior()->next();
0260       x->prior()->next()=buc;
0261       buc->prior()=x;
0262       end->prior()=x;
0263     }
0264     else{
0265       x->prior()=buc->prior()->prior();
0266       x->next()=base_pointer_from(buc->prior());
0267       buc->prior()=x;
0268       x->next()->prior()=x;
0269     }
0270   }
0271 
0272   static void unlink(pointer x)
0273   {
0274     default_assigner assign;
0275     unlink(x,assign);
0276   }
0277 
0278   typedef unlink_undo_assigner<Node> unlink_undo;
0279 
0280   template<typename Assigner>
0281   static void unlink(pointer x,Assigner& assign)
0282   {
0283     if(is_first_of_bucket(x)){
0284       if(is_last_of_bucket(x)){
0285         assign(x->prior()->next()->prior(),pointer(0));
0286         assign(x->prior()->next(),x->next());
0287         assign(x->next()->prior()->prior(),x->prior());
0288       }
0289       else{
0290         assign(x->prior()->next()->prior(),pointer_from(x->next()));
0291         assign(x->next()->prior(),x->prior());
0292       }
0293     }
0294     else if(is_last_of_bucket(x)){
0295       assign(x->prior()->next(),x->next());
0296       assign(x->next()->prior()->prior(),x->prior());
0297     }
0298     else{
0299       assign(x->prior()->next(),x->next());
0300       assign(x->next()->prior(),x->prior());
0301     }
0302   }
0303 
0304   /* used only at rehashing */
0305 
0306   static void append(pointer x,pointer end)
0307   {
0308     x->prior()=end->prior();
0309     x->next()=end->prior()->next();
0310     x->prior()->next()=base_pointer_from(x);
0311     end->prior()=x;
0312   }
0313 
0314   static bool unlink_last(pointer end)
0315   {
0316     /* returns true iff bucket is emptied */
0317 
0318     pointer x=end->prior();
0319     if(x->prior()->next()==base_pointer_from(x)){
0320       x->prior()->next()=x->next();
0321       end->prior()=x->prior();
0322       return false;
0323     }
0324     else{
0325       x->prior()->next()->prior()=pointer(0);
0326       x->prior()->next()=x->next();
0327       end->prior()=x->prior();
0328       return true;
0329     }
0330   }
0331 
0332 private:
0333   static pointer pointer_from(base_pointer x)
0334   {
0335     return Node::pointer_from(x);
0336   }
0337 
0338   static base_pointer base_pointer_from(pointer x)
0339   {
0340     return Node::base_pointer_from(x);
0341   }
0342 
0343   static bool is_last_of_bucket(pointer x)
0344   {
0345     return x->next()->prior()!=x;
0346   }
0347 };
0348 
0349 template<typename Node>
0350 struct hashed_index_node_alg<Node,hashed_non_unique_tag>
0351 {
0352   typedef typename Node::base_pointer       base_pointer;
0353   typedef typename Node::const_base_pointer const_base_pointer;
0354   typedef typename Node::pointer            pointer;
0355   typedef typename Node::const_pointer      const_pointer;
0356 
0357   static bool is_first_of_bucket(pointer x)
0358   {
0359     return x->prior()->next()->prior()==x;
0360   }
0361 
0362   static bool is_first_of_group(pointer x)
0363   {
0364     return
0365       x->next()->prior()!=x&&
0366       x->next()->prior()->prior()->next()==base_pointer_from(x);
0367   }
0368 
0369   static pointer after(pointer x)
0370   {
0371     if(x->next()->prior()==x)return pointer_from(x->next());
0372     if(x->next()->prior()->prior()==x)return x->next()->prior();
0373     if(x->next()->prior()->prior()->next()==base_pointer_from(x))
0374       return pointer_from(x->next());
0375     return pointer_from(x->next())->next()->prior();
0376   }
0377 
0378   static pointer after_local(pointer x)
0379   {
0380     if(x->next()->prior()==x)return pointer_from(x->next());
0381     if(x->next()->prior()->prior()==x)return pointer(0);
0382     if(x->next()->prior()->prior()->next()==base_pointer_from(x))
0383       return pointer_from(x->next());
0384     return pointer_from(x->next())->next()->prior();
0385   }
0386 
0387   static pointer next_to_inspect(pointer x)
0388   {
0389     if(x->next()->prior()==x)return pointer_from(x->next());
0390     if(x->next()->prior()->prior()==x)return pointer(0);
0391     if(x->next()->prior()->next()->prior()!=x->next()->prior())
0392       return pointer(0);
0393     return pointer_from(x->next()->prior()->next());
0394   }
0395 
0396   static void link(pointer x,base_pointer buc,pointer end)
0397   {
0398     if(buc->prior()==pointer(0)){ /* empty bucket */
0399       x->prior()=end->prior();
0400       x->next()=end->prior()->next();
0401       x->prior()->next()=buc;
0402       buc->prior()=x;
0403       end->prior()=x;
0404     }
0405     else{
0406       x->prior()=buc->prior()->prior();
0407       x->next()=base_pointer_from(buc->prior());
0408       buc->prior()=x;
0409       x->next()->prior()=x;
0410     }
0411   }
0412 
0413   static void link(pointer x,pointer first,pointer last)
0414   {
0415     x->prior()=first->prior();
0416     x->next()=base_pointer_from(first);
0417     if(is_first_of_bucket(first)){
0418       x->prior()->next()->prior()=x;
0419     }
0420     else{
0421       x->prior()->next()=base_pointer_from(x);
0422     }
0423 
0424     if(first==last){
0425       last->prior()=x;
0426     }
0427     else if(first->next()==base_pointer_from(last)){
0428       first->prior()=last;
0429       first->next()=base_pointer_from(x);
0430     }
0431     else{
0432       pointer second=pointer_from(first->next()),
0433               lastbutone=last->prior();
0434       second->prior()=first;
0435       first->prior()=last;
0436       lastbutone->next()=base_pointer_from(x);
0437     }
0438   }
0439 
0440   static void unlink(pointer x)
0441   {
0442     default_assigner assign;
0443     unlink(x,assign);
0444   }
0445 
0446   typedef unlink_undo_assigner<Node> unlink_undo;
0447 
0448   template<typename Assigner>
0449   static void unlink(pointer x,Assigner& assign)
0450   {
0451     if(x->prior()->next()==base_pointer_from(x)){
0452       if(x->next()->prior()==x){
0453         left_unlink(x,assign);
0454         right_unlink(x,assign);
0455       }
0456       else if(x->next()->prior()->prior()==x){           /* last of bucket */
0457         left_unlink(x,assign);
0458         right_unlink_last_of_bucket(x,assign);
0459       }
0460       else if(x->next()->prior()->prior()->next()==
0461               base_pointer_from(x)){                /* first of group size */
0462         left_unlink(x,assign);
0463         right_unlink_first_of_group(x,assign);
0464       }
0465       else{                                                /* n-1 of group */
0466         unlink_last_but_one_of_group(x,assign);
0467       }
0468     }
0469     else if(x->prior()->next()->prior()==x){            /* first of bucket */
0470       if(x->next()->prior()==x){
0471         left_unlink_first_of_bucket(x,assign);
0472         right_unlink(x,assign);
0473       }
0474       else if(x->next()->prior()->prior()==x){           /* last of bucket */
0475         assign(x->prior()->next()->prior(),pointer(0));
0476         assign(x->prior()->next(),x->next());
0477         assign(x->next()->prior()->prior(),x->prior());
0478       }
0479       else{                                              /* first of group */
0480         left_unlink_first_of_bucket(x,assign);
0481         right_unlink_first_of_group(x,assign);
0482       }
0483     }
0484     else if(x->next()->prior()->prior()==x){   /* last of group and bucket */
0485       left_unlink_last_of_group(x,assign);
0486       right_unlink_last_of_bucket(x,assign);
0487     }
0488     else if(pointer_from(x->prior()->prior()->next())
0489             ->next()==base_pointer_from(x)){            /* second of group */
0490       unlink_second_of_group(x,assign);
0491     }
0492     else{                              /* last of group, ~(last of bucket) */
0493       left_unlink_last_of_group(x,assign);
0494       right_unlink(x,assign);
0495     }
0496   }
0497 
0498   /* used only at rehashing */
0499 
0500   static void link_range(
0501     pointer first,pointer last,base_pointer buc,pointer cend)
0502   {
0503     if(buc->prior()==pointer(0)){ /* empty bucket */
0504       first->prior()=cend->prior();
0505       last->next()=cend->prior()->next();
0506       first->prior()->next()=buc;
0507       buc->prior()=first;
0508       cend->prior()=last;
0509     }
0510     else{
0511       first->prior()=buc->prior()->prior();
0512       last->next()=base_pointer_from(buc->prior());
0513       buc->prior()=first;
0514       last->next()->prior()=last;
0515     }
0516   }
0517 
0518   static void append_range(pointer first,pointer last,pointer cend)
0519   {
0520     first->prior()=cend->prior();
0521     last->next()=cend->prior()->next();
0522     first->prior()->next()=base_pointer_from(first);
0523     cend->prior()=last;
0524   }
0525 
0526   static std::pair<pointer,bool> unlink_last_group(pointer end)
0527   {
0528     /* returns first of group true iff bucket is emptied */
0529 
0530     pointer x=end->prior();
0531     if(x->prior()->next()==base_pointer_from(x)){
0532       x->prior()->next()=x->next();
0533       end->prior()=x->prior();
0534       return std::make_pair(x,false);
0535     }
0536     else if(x->prior()->next()->prior()==x){
0537       x->prior()->next()->prior()=pointer(0);
0538       x->prior()->next()=x->next();
0539       end->prior()=x->prior();
0540       return std::make_pair(x,true);
0541     }
0542     else{
0543       pointer y=pointer_from(x->prior()->next());
0544 
0545       if(y->prior()->next()==base_pointer_from(y)){
0546         y->prior()->next()=x->next();
0547         end->prior()=y->prior();
0548         return std::make_pair(y,false);
0549       }
0550       else{
0551         y->prior()->next()->prior()=pointer(0);
0552         y->prior()->next()=x->next();
0553         end->prior()=y->prior();
0554         return std::make_pair(y,true);
0555       }
0556     }
0557   }
0558 
0559   static void unlink_range(pointer first,pointer last)
0560   {
0561     if(is_first_of_bucket(first)){
0562       if(is_last_of_bucket(last)){
0563         first->prior()->next()->prior()=pointer(0);
0564         first->prior()->next()=last->next();
0565         last->next()->prior()->prior()=first->prior();
0566       }
0567       else{
0568         first->prior()->next()->prior()=pointer_from(last->next());
0569         last->next()->prior()=first->prior();
0570       }
0571     }
0572     else if(is_last_of_bucket(last)){
0573       first->prior()->next()=last->next();
0574       last->next()->prior()->prior()=first->prior();
0575     }
0576     else{
0577       first->prior()->next()=last->next();
0578       last->next()->prior()=first->prior();
0579     }
0580   }
0581 
0582 private:
0583   static pointer pointer_from(base_pointer x)
0584   {
0585     return Node::pointer_from(x);
0586   }
0587 
0588   static base_pointer base_pointer_from(pointer x)
0589   {
0590     return Node::base_pointer_from(x);
0591   }
0592 
0593   static bool is_last_of_bucket(pointer x)
0594   {
0595     return x->next()->prior()->prior()==x;
0596   }
0597 
0598   template<typename Assigner>
0599   static void left_unlink(pointer x,Assigner& assign)
0600   {
0601     assign(x->prior()->next(),x->next());
0602   }
0603   
0604   template<typename Assigner>
0605   static void right_unlink(pointer x,Assigner& assign)
0606   {
0607     assign(x->next()->prior(),x->prior());
0608   }
0609 
0610   template<typename Assigner>
0611   static void left_unlink_first_of_bucket(pointer x,Assigner& assign)
0612   {
0613     assign(x->prior()->next()->prior(),pointer_from(x->next()));
0614   }
0615 
0616   template<typename Assigner>
0617   static void right_unlink_last_of_bucket(pointer x,Assigner& assign)
0618   {
0619     assign(x->next()->prior()->prior(),x->prior());
0620   }
0621 
0622   template<typename Assigner>
0623   static void right_unlink_first_of_group(pointer x,Assigner& assign)
0624   {
0625     pointer second=pointer_from(x->next()),
0626             last=second->prior(),
0627             lastbutone=last->prior();
0628     if(second==lastbutone){
0629       assign(second->next(),base_pointer_from(last));
0630       assign(second->prior(),x->prior());
0631     }
0632     else{
0633       assign(lastbutone->next(),base_pointer_from(second));
0634       assign(second->next()->prior(),last);
0635       assign(second->prior(),x->prior());
0636     }
0637   }
0638 
0639   template<typename Assigner>
0640   static void left_unlink_last_of_group(pointer x,Assigner& assign)
0641   {
0642     pointer lastbutone=x->prior(),
0643             first=pointer_from(lastbutone->next()),
0644             second=pointer_from(first->next());
0645     if(lastbutone==second){
0646       assign(lastbutone->prior(),first);
0647       assign(lastbutone->next(),x->next());
0648     }
0649     else{
0650       assign(second->prior(),lastbutone);
0651       assign(lastbutone->prior()->next(),base_pointer_from(first));
0652       assign(lastbutone->next(),x->next());
0653     }
0654   }
0655 
0656   template<typename Assigner>
0657   static void unlink_last_but_one_of_group(pointer x,Assigner& assign)
0658   {
0659     pointer first=pointer_from(x->next()),
0660             second=pointer_from(first->next()),
0661             last=second->prior();
0662     if(second==x){
0663       assign(last->prior(),first);
0664       assign(first->next(),base_pointer_from(last));
0665     }
0666     else{
0667       assign(last->prior(),x->prior());
0668       assign(x->prior()->next(),base_pointer_from(first));
0669     }
0670   }
0671 
0672   template<typename Assigner>
0673   static void unlink_second_of_group(pointer x,Assigner& assign)
0674   {
0675     pointer last=x->prior(),
0676             lastbutone=last->prior(),
0677             first=pointer_from(lastbutone->next());
0678     if(lastbutone==x){
0679       assign(first->next(),base_pointer_from(last));
0680       assign(last->prior(),first);
0681     }
0682     else{
0683       assign(first->next(),x->next());
0684       assign(x->next()->prior(),last);
0685     }
0686   }
0687 };
0688 
0689 template<typename Super>
0690 struct hashed_index_node_trampoline:
0691   hashed_index_node_impl<
0692     typename rebind_alloc_for<
0693       typename Super::allocator_type,char
0694     >::type
0695   >
0696 {
0697   typedef typename rebind_alloc_for<
0698     typename Super::allocator_type,char
0699   >::type                                             impl_allocator_type;
0700   typedef hashed_index_node_impl<impl_allocator_type> impl_type;
0701 };
0702 
0703 template<typename Super>
0704 struct hashed_index_node:
0705   Super,hashed_index_node_trampoline<Super>
0706 {
0707 private:
0708   typedef hashed_index_node_trampoline<Super> trampoline;
0709 
0710 public:
0711   typedef typename trampoline::impl_type          impl_type;
0712   typedef typename trampoline::base_pointer       impl_base_pointer;
0713   typedef typename trampoline::const_base_pointer const_impl_base_pointer;
0714   typedef typename trampoline::pointer            impl_pointer;
0715   typedef typename trampoline::const_pointer      const_impl_pointer;
0716   typedef typename trampoline::difference_type    difference_type;
0717 
0718   template<typename Category>
0719   struct node_alg{
0720     typedef hashed_index_node_alg<impl_type,Category> type;
0721   };
0722 
0723   impl_pointer&      prior(){return trampoline::prior();}
0724   impl_pointer       prior()const{return trampoline::prior();}
0725   impl_base_pointer& next(){return trampoline::next();}
0726   impl_base_pointer  next()const{return trampoline::next();}
0727 
0728   impl_pointer impl()
0729   {
0730     return static_cast<impl_pointer>(
0731       static_cast<impl_type*>(static_cast<trampoline*>(this)));
0732   }
0733 
0734   const_impl_pointer impl()const
0735   {
0736     return static_cast<const_impl_pointer>(
0737       static_cast<const impl_type*>(static_cast<const trampoline*>(this)));
0738   }
0739 
0740   static hashed_index_node* from_impl(impl_pointer x)
0741   {
0742     return
0743       static_cast<hashed_index_node*>(
0744         static_cast<trampoline*>(
0745           raw_ptr<impl_type*>(x)));
0746   }
0747 
0748   static const hashed_index_node* from_impl(const_impl_pointer x)
0749   {
0750     return 
0751       static_cast<const hashed_index_node*>(
0752         static_cast<const trampoline*>(
0753           raw_ptr<const impl_type*>(x)));
0754   }
0755 
0756   /* interoperability with hashed_index_iterator */
0757 
0758   template<typename Category>
0759   static void increment(hashed_index_node*& x)
0760   {
0761     x=from_impl(node_alg<Category>::type::after(x->impl()));
0762   }
0763 
0764   template<typename Category>
0765   static void increment_local(hashed_index_node*& x)
0766   {
0767     x=from_impl(node_alg<Category>::type::after_local(x->impl()));
0768   }
0769 };
0770 
0771 } /* namespace multi_index::detail */
0772 
0773 } /* namespace multi_index */
0774 
0775 } /* namespace boost */
0776 
0777 #endif