80c43ee5b262676edcbb3a9d1d3391cc3904391f
[libcds.git] / cds / intrusive / impl / skip_list.h
1 /*
2     This file is a part of libcds - Concurrent Data Structures library
3
4     (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
5
6     Source code repo: http://github.com/khizmax/libcds/
7     Download: http://sourceforge.net/projects/libcds/files/
8
9     Redistribution and use in source and binary forms, with or without
10     modification, are permitted provided that the following conditions are met:
11
12     * Redistributions of source code must retain the above copyright notice, this
13       list of conditions and the following disclaimer.
14
15     * Redistributions in binary form must reproduce the above copyright notice,
16       this list of conditions and the following disclaimer in the documentation
17       and/or other materials provided with the distribution.
18
19     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20     AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21     IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23     FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24     DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28     OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #ifndef CDSLIB_INTRUSIVE_IMPL_SKIP_LIST_H
32 #define CDSLIB_INTRUSIVE_IMPL_SKIP_LIST_H
33
34 #include <type_traits>
35 #include <memory>
36 #include <functional>   // ref
37 #include <cds/intrusive/details/skip_list_base.h>
38 #include <cds/opt/compare.h>
39 #include <cds/details/binary_functor_wrapper.h>
40
41 namespace cds { namespace intrusive {
42
43     //@cond
44     namespace skip_list { namespace details {
45
46         template <class GC, typename NodeTraits, typename BackOff, bool IsConst>
47         class iterator {
48         public:
49             typedef GC                                  gc;
50             typedef NodeTraits                          node_traits;
51             typedef BackOff                             back_off;
52             typedef typename node_traits::node_type     node_type;
53             typedef typename node_traits::value_type    value_type;
54             static CDS_CONSTEXPR bool const c_isConst = IsConst;
55
56             typedef typename std::conditional< c_isConst, value_type const&, value_type&>::type   value_ref;
57
58         protected:
59             typedef typename node_type::marked_ptr          marked_ptr;
60             typedef typename node_type::atomic_marked_ptr   atomic_marked_ptr;
61
62             typename gc::Guard      m_guard;
63             node_type *             m_pNode;
64
65         protected:
66             static value_type * gc_protect( marked_ptr p )
67             {
68                 return node_traits::to_value_ptr( p.ptr());
69             }
70
71             void next()
72             {
73                 typename gc::Guard g;
74                 g.copy( m_guard );
75                 back_off bkoff;
76
77                 for (;;) {
78                     if ( m_pNode->next( m_pNode->height() - 1 ).load( atomics::memory_order_acquire ).bits()) {
79                         // Current node is marked as deleted. So, its next pointer can point to anything
80                         // In this case we interrupt our iteration and returns end() iterator.
81                         *this = iterator();
82                         return;
83                     }
84
85                     marked_ptr p = m_guard.protect( (*m_pNode)[0], gc_protect );
86                     node_type * pp = p.ptr();
87                     if ( p.bits()) {
88                         // p is marked as deleted. Spin waiting for physical removal
89                         bkoff();
90                         continue;
91                     }
92                     else if ( pp && pp->next( pp->height() - 1 ).load( atomics::memory_order_relaxed ).bits()) {
93                         // p is marked as deleted. Spin waiting for physical removal
94                         bkoff();
95                         continue;
96                     }
97
98                     m_pNode = pp;
99                     break;
100                 }
101             }
102
103         public: // for internal use only!!!
104             iterator( node_type& refHead )
105                 : m_pNode( nullptr )
106             {
107                 back_off bkoff;
108
109                 for (;;) {
110                     marked_ptr p = m_guard.protect( refHead[0], gc_protect );
111                     if ( !p.ptr()) {
112                         // empty skip-list
113                         m_guard.clear();
114                         break;
115                     }
116
117                     node_type * pp = p.ptr();
118                     // Logically deleted node is marked from highest level
119                     if ( !pp->next( pp->height() - 1 ).load( atomics::memory_order_acquire ).bits()) {
120                         m_pNode = pp;
121                         break;
122                     }
123
124                     bkoff();
125                 }
126             }
127
128         public:
129             iterator()
130                 : m_pNode( nullptr )
131             {}
132
133             iterator( iterator const& s)
134                 : m_pNode( s.m_pNode )
135             {
136                 m_guard.assign( node_traits::to_value_ptr(m_pNode));
137             }
138
139             value_type * operator ->() const
140             {
141                 assert( m_pNode != nullptr );
142                 assert( node_traits::to_value_ptr( m_pNode ) != nullptr );
143
144                 return node_traits::to_value_ptr( m_pNode );
145             }
146
147             value_ref operator *() const
148             {
149                 assert( m_pNode != nullptr );
150                 assert( node_traits::to_value_ptr( m_pNode ) != nullptr );
151
152                 return *node_traits::to_value_ptr( m_pNode );
153             }
154
155             /// Pre-increment
156             iterator& operator ++()
157             {
158                 next();
159                 return *this;
160             }
161
162             iterator& operator =(const iterator& src)
163             {
164                 m_pNode = src.m_pNode;
165                 m_guard.copy( src.m_guard );
166                 return *this;
167             }
168
169             template <typename Bkoff, bool C>
170             bool operator ==(iterator<gc, node_traits, Bkoff, C> const& i ) const
171             {
172                 return m_pNode == i.m_pNode;
173             }
174             template <typename Bkoff, bool C>
175             bool operator !=(iterator<gc, node_traits, Bkoff, C> const& i ) const
176             {
177                 return !( *this == i );
178             }
179         };
180     }}  // namespace skip_list::details
181     //@endcond
182
183     /// Lock-free skip-list set
184     /** @ingroup cds_intrusive_map
185         @anchor cds_intrusive_SkipListSet_hp
186
187         The implementation of well-known probabilistic data structure called skip-list
188         invented by W.Pugh in his papers:
189             - [1989] W.Pugh Skip Lists: A Probabilistic Alternative to Balanced Trees
190             - [1990] W.Pugh A Skip List Cookbook
191
192         A skip-list is a probabilistic data structure that provides expected logarithmic
193         time search without the need of rebalance. The skip-list is a collection of sorted
194         linked list. Nodes are ordered by key. Each node is linked into a subset of the lists.
195         Each list has a level, ranging from 0 to 32. The bottom-level list contains
196         all the nodes, and each higher-level list is a sublist of the lower-level lists.
197         Each node is created with a random top level (with a random height), and belongs
198         to all lists up to that level. The probability that a node has the height 1 is 1/2.
199         The probability that a node has the height N is 1/2 ** N (more precisely,
200         the distribution depends on an random generator provided, but our generators
201         have this property).
202
203         The lock-free variant of skip-list is implemented according to book
204             - [2008] M.Herlihy, N.Shavit "The Art of Multiprocessor Programming",
205                 chapter 14.4 "A Lock-Free Concurrent Skiplist".
206
207         <b>Template arguments</b>:
208             - \p GC - Garbage collector used. Note the \p GC must be the same as the GC used for item type \p T, see \p skip_list::node.
209             - \p T - type to be stored in the list. The type must be based on \p skip_list::node (for \p skip_list::base_hook)
210                 or it must have a member of type \p skip_list::node (for \p skip_list::member_hook).
211             - \p Traits - skip-list traits, default is \p skip_list::traits.
212                 It is possible to declare option-based list with \p cds::intrusive::skip_list::make_traits metafunction istead of \p Traits
213                 template argument.
214
215         @warning The skip-list requires up to 67 hazard pointers that may be critical for some GCs for which
216             the guard count is limited (like as \p gc::HP). Those GCs should be explicitly initialized with
217             hazard pointer enough: \code cds::gc::HP myhp( 67 ) \endcode. Otherwise an run-time exception may be raised
218             when you try to create skip-list object.
219
220         There are several specializations of \p %SkipListSet for each \p GC. You should include:
221         - <tt><cds/intrusive/skip_list_hp.h></tt> for \p gc::HP garbage collector
222         - <tt><cds/intrusive/skip_list_dhp.h></tt> for \p gc::DHP garbage collector
223         - <tt><cds/intrusive/skip_list_nogc.h></tt> for \ref cds_intrusive_SkipListSet_nogc for append-only set
224         - <tt><cds/intrusive/skip_list_rcu.h></tt> for \ref cds_intrusive_SkipListSet_rcu "RCU type"
225
226         <b>Iterators</b>
227
228         The class supports a forward iterator (\ref iterator and \ref const_iterator).
229         The iteration is ordered.
230         The iterator object is thread-safe: the element pointed by the iterator object is guarded,
231         so, the element cannot be reclaimed while the iterator object is alive.
232         However, passing an iterator object between threads is dangerous.
233
234         @warning Due to concurrent nature of skip-list set it is not guarantee that you can iterate
235         all elements in the set: any concurrent deletion can exclude the element
236         pointed by the iterator from the set, and your iteration can be terminated
237         before end of the set. Therefore, such iteration is more suitable for debugging purpose only
238
239         Remember, each iterator object requires 2 additional hazard pointers, that may be
240         a limited resource for \p GC like as \p gc::HP (for \p gc::DHP the count of
241         guards is unlimited).
242
243         The iterator class supports the following minimalistic interface:
244         \code
245         struct iterator {
246             // Default ctor
247             iterator();
248
249             // Copy ctor
250             iterator( iterator const& s);
251
252             value_type * operator ->() const;
253             value_type& operator *() const;
254
255             // Pre-increment
256             iterator& operator ++();
257
258             // Copy assignment
259             iterator& operator = (const iterator& src);
260
261             bool operator ==(iterator const& i ) const;
262             bool operator !=(iterator const& i ) const;
263         };
264         \endcode
265         Note, the iterator object returned by \p end(), \p cend() member functions points to \p nullptr and should not be dereferenced.
266
267         <b>How to use</b>
268
269         You should incorporate \p skip_list::node into your struct \p T and provide
270         appropriate \p skip_list::traits::hook in your \p Traits template parameters. Usually, for \p Traits you
271         define a struct based on \p skip_list::traits.
272
273         Example for \p gc::HP and base hook:
274         \code
275         // Include GC-related skip-list specialization
276         #include <cds/intrusive/skip_list_hp.h>
277
278         // Data stored in skip list
279         struct my_data: public cds::intrusive::skip_list::node< cds::gc::HP >
280         {
281             // key field
282             std::string     strKey;
283
284             // other data
285             // ...
286         };
287
288         // my_data compare functor
289         struct my_data_cmp {
290             int operator()( const my_data& d1, const my_data& d2 )
291             {
292                 return d1.strKey.compare( d2.strKey );
293             }
294
295             int operator()( const my_data& d, const std::string& s )
296             {
297                 return d.strKey.compare(s);
298             }
299
300             int operator()( const std::string& s, const my_data& d )
301             {
302                 return s.compare( d.strKey );
303             }
304         };
305
306
307         // Declare your traits
308         struct my_traits: public cds::intrusive::skip_list::traits
309         {
310             typedef cds::intrusive::skip_list::base_hook< cds::opt::gc< cds::gc::HP > >   hook;
311             typedef my_data_cmp compare;
312         };
313
314         // Declare skip-list set type
315         typedef cds::intrusive::SkipListSet< cds::gc::HP, my_data, my_traits >     traits_based_set;
316         \endcode
317
318         Equivalent option-based code:
319         \code
320         // GC-related specialization
321         #include <cds/intrusive/skip_list_hp.h>
322
323         struct my_data {
324             // see above
325         };
326         struct compare {
327             // see above
328         };
329
330         // Declare option-based skip-list set
331         typedef cds::intrusive::SkipListSet< cds::gc::HP
332             ,my_data
333             , typename cds::intrusive::skip_list::make_traits<
334                 cds::intrusive::opt::hook< cds::intrusive::skip_list::base_hook< cds::opt::gc< cds::gc::HP > > >
335                 ,cds::intrusive::opt::compare< my_data_cmp >
336             >::type
337         > option_based_set;
338
339         \endcode
340     */
341     template <
342         class GC
343        ,typename T
344 #ifdef CDS_DOXYGEN_INVOKED
345        ,typename Traits = skip_list::traits
346 #else
347        ,typename Traits
348 #endif
349     >
350     class SkipListSet
351     {
352     public:
353         typedef GC      gc;         ///< Garbage collector
354         typedef T       value_type; ///< type of value stored in the skip-list
355         typedef Traits  traits;     ///< Traits template parameter
356
357         typedef typename traits::hook    hook;      ///< hook type
358         typedef typename hook::node_type node_type; ///< node type
359
360 #   ifdef CDS_DOXYGEN_INVOKED
361         typedef implementation_defined key_comparator  ;    ///< key comparison functor based on opt::compare and opt::less option setter.
362 #   else
363         typedef typename opt::details::make_comparator< value_type, traits >::type key_comparator;
364 #   endif
365
366         typedef typename traits::disposer  disposer;   ///< item disposer
367         typedef typename get_node_traits< value_type, node_type, hook>::type node_traits; ///< node traits
368
369         typedef typename traits::item_counter  item_counter;   ///< Item counting policy
370         typedef typename traits::memory_model  memory_model;   ///< Memory ordering, see \p cds::opt::memory_model option
371         typedef typename traits::random_level_generator random_level_generator; ///< random level generator
372         typedef typename traits::allocator     allocator_type;   ///< allocator for maintaining array of next pointers of the node
373         typedef typename traits::back_off      back_off;   ///< Back-off strategy
374         typedef typename traits::stat          stat;       ///< internal statistics type
375
376     public:
377         typedef typename gc::template guarded_ptr< value_type > guarded_ptr; ///< Guarded pointer
378
379         /// Max node height. The actual node height should be in range <tt>[0 .. c_nMaxHeight)</tt>
380         /**
381             The max height is specified by \ref skip_list::random_level_generator "random level generator" constant \p m_nUpperBound
382             but it should be no more than 32 (\p skip_list::c_nHeightLimit).
383         */
384         static unsigned int const c_nMaxHeight = std::conditional<
385             (random_level_generator::c_nUpperBound <= skip_list::c_nHeightLimit),
386             std::integral_constant< unsigned int, random_level_generator::c_nUpperBound >,
387             std::integral_constant< unsigned int, skip_list::c_nHeightLimit >
388         >::type::value;
389
390         //@cond
391         static unsigned int const c_nMinHeight = 5;
392         //@endcond
393
394         // c_nMaxHeight * 2 - pPred/pSucc guards
395         // + 1 - for erase, unlink
396         // + 1 - for clear
397         static size_t const c_nHazardPtrCount = c_nMaxHeight * 2 + 2; ///< Count of hazard pointer required for the skip-list
398
399     protected:
400         typedef typename node_type::atomic_marked_ptr   atomic_node_ptr;   ///< Atomic marked node pointer
401         typedef typename node_type::marked_ptr          marked_node_ptr;   ///< Node marked pointer
402
403     protected:
404         //@cond
405         typedef skip_list::details::intrusive_node_builder< node_type, atomic_node_ptr, allocator_type > intrusive_node_builder;
406
407         typedef typename std::conditional<
408             std::is_same< typename traits::internal_node_builder, cds::opt::none >::value
409             ,intrusive_node_builder
410             ,typename traits::internal_node_builder
411         >::type node_builder;
412
413         typedef std::unique_ptr< node_type, typename node_builder::node_disposer > scoped_node_ptr;
414
415         struct position {
416             node_type *   pPrev[ c_nMaxHeight ];
417             node_type *   pSucc[ c_nMaxHeight ];
418
419             typename gc::template GuardArray< c_nMaxHeight * 2 > guards;   ///< Guards array for pPrev/pSucc
420             node_type *   pCur;   // guarded by one of guards
421         };
422         //@endcond
423
424     public:
425         /// Default constructor
426         /**
427             The constructor checks whether the count of guards is enough
428             for skip-list and may raise an exception if not.
429         */
430         SkipListSet()
431             : m_Head( c_nMaxHeight )
432             , m_nHeight( c_nMinHeight )
433         {
434             static_assert( (std::is_same< gc, typename node_type::gc >::value), "GC and node_type::gc must be the same type" );
435
436             gc::check_available_guards( c_nHazardPtrCount );
437
438             // Barrier for head node
439             atomics::atomic_thread_fence( memory_model::memory_order_release );
440         }
441
442         /// Clears and destructs the skip-list
443         ~SkipListSet()
444         {
445             clear();
446         }
447
448     public:
449     ///@name Forward iterators (only for debugging purpose)
450     //@{
451         /// Iterator type
452         /**
453             The forward iterator has some features:
454             - it has no post-increment operator
455             - to protect the value, the iterator contains a GC-specific guard + another guard is required locally for increment operator.
456               For some GC (like as \p gc::HP), a guard is a limited resource per thread, so an exception (or assertion) "no free guard"
457               may be thrown if the limit of guard count per thread is exceeded.
458             - The iterator cannot be moved across thread boundary because it contains thread-private GC's guard.
459             - Iterator ensures thread-safety even if you delete the item the iterator points to. However, in case of concurrent
460               deleting operations there is no guarantee that you iterate all item in the list.
461               Moreover, a crash is possible when you try to iterate the next element that has been deleted by concurrent thread.
462
463             @warning Use this iterator on the concurrent container for debugging purpose only.
464
465             The iterator interface:
466             \code
467             class iterator {
468             public:
469                 // Default constructor
470                 iterator();
471
472                 // Copy construtor
473                 iterator( iterator const& src );
474
475                 // Dereference operator
476                 value_type * operator ->() const;
477
478                 // Dereference operator
479                 value_type& operator *() const;
480
481                 // Preincrement operator
482                 iterator& operator ++();
483
484                 // Assignment operator
485                 iterator& operator = (iterator const& src);
486
487                 // Equality operators
488                 bool operator ==(iterator const& i ) const;
489                 bool operator !=(iterator const& i ) const;
490             };
491             \endcode
492         */
493         typedef skip_list::details::iterator< gc, node_traits, back_off, false >  iterator;
494
495         /// Const iterator type
496         typedef skip_list::details::iterator< gc, node_traits, back_off, true >   const_iterator;
497
498         /// Returns a forward iterator addressing the first element in a set
499         iterator begin()
500         {
501             return iterator( *m_Head.head());
502         }
503
504         /// Returns a forward const iterator addressing the first element in a set
505         const_iterator begin() const
506         {
507             return const_iterator( *m_Head.head());
508         }
509         /// Returns a forward const iterator addressing the first element in a set
510         const_iterator cbegin() const
511         {
512             return const_iterator( *m_Head.head());
513         }
514
515         /// Returns a forward iterator that addresses the location succeeding the last element in a set.
516         iterator end()
517         {
518             return iterator();
519         }
520
521         /// Returns a forward const iterator that addresses the location succeeding the last element in a set.
522         const_iterator end() const
523         {
524             return const_iterator();
525         }
526         /// Returns a forward const iterator that addresses the location succeeding the last element in a set.
527         const_iterator cend() const
528         {
529             return const_iterator();
530         }
531     //@}
532
533     public:
534         /// Inserts new node
535         /**
536             The function inserts \p val in the set if it does not contain
537             an item with key equal to \p val.
538
539             Returns \p true if \p val is placed into the set, \p false otherwise.
540         */
541         bool insert( value_type& val )
542         {
543             return insert( val, []( value_type& ) {} );
544         }
545
546         /// Inserts new node
547         /**
548             This function is intended for derived non-intrusive containers.
549
550             The function allows to split creating of new item into two part:
551             - create item with key only
552             - insert new item into the set
553             - if inserting is success, calls  \p f functor to initialize value-field of \p val.
554
555             The functor signature is:
556             \code
557                 void func( value_type& val );
558             \endcode
559             where \p val is the item inserted. User-defined functor \p f should guarantee that during changing
560             \p val no any other changes could be made on this set's item by concurrent threads.
561             The user-defined functor is called only if the inserting is success.
562         */
563         template <typename Func>
564         bool insert( value_type& val, Func f )
565         {
566             typename gc::Guard gNew;
567             gNew.assign( &val );
568
569             node_type * pNode = node_traits::to_node_ptr( val );
570             scoped_node_ptr scp( pNode );
571             unsigned int nHeight = pNode->height();
572             bool bTowerOk = pNode->has_tower(); // nHeight > 1 && pNode->get_tower() != nullptr;
573             bool bTowerMade = false;
574
575             position pos;
576             while ( true )
577             {
578                 if ( find_position( val, pos, key_comparator(), true )) {
579                     // scoped_node_ptr deletes the node tower if we create it
580                     if ( !bTowerMade )
581                         scp.release();
582
583                     m_Stat.onInsertFailed();
584                     return false;
585                 }
586
587                 if ( !bTowerOk ) {
588                     build_node( pNode );
589                     nHeight = pNode->height();
590                     bTowerMade = pNode->has_tower();
591                     bTowerOk = true;
592                 }
593
594                 if ( !insert_at_position( val, pNode, pos, f )) {
595                     m_Stat.onInsertRetry();
596                     continue;
597                 }
598
599                 increase_height( nHeight );
600                 ++m_ItemCounter;
601                 m_Stat.onAddNode( nHeight );
602                 m_Stat.onInsertSuccess();
603                 scp.release();
604                 return true;
605             }
606         }
607
608         /// Updates the node
609         /**
610             The operation performs inserting or changing data with lock-free manner.
611
612             If the item \p val is not found in the set, then \p val is inserted into the set
613             iff \p bInsert is \p true.
614             Otherwise, the functor \p func is called with item found.
615             The functor \p func signature is:
616             \code
617                 void func( bool bNew, value_type& item, value_type& val );
618             \endcode
619             with arguments:
620             - \p bNew - \p true if the item has been inserted, \p false otherwise
621             - \p item - item of the set
622             - \p val - argument \p val passed into the \p %update() function
623             If new item has been inserted (i.e. \p bNew is \p true) then \p item and \p val arguments
624             refer to the same thing.
625
626             Returns std::pair<bool, bool> where \p first is \p true if operation is successful,
627             i.e. the node has been inserted or updated,
628             \p second is \p true if new item has been added or \p false if the item with \p key
629             already exists.
630
631             @warning See \ref cds_intrusive_item_creating "insert item troubleshooting"
632         */
633         template <typename Func>
634         std::pair<bool, bool> update( value_type& val, Func func, bool bInsert = true )
635         {
636             typename gc::Guard gNew;
637             gNew.assign( &val );
638
639             node_type * pNode = node_traits::to_node_ptr( val );
640             scoped_node_ptr scp( pNode );
641             unsigned int nHeight = pNode->height();
642             bool bTowerOk = pNode->has_tower();
643             bool bTowerMade = false;
644
645             position pos;
646             while ( true )
647             {
648                 bool bFound = find_position( val, pos, key_comparator(), true );
649                 if ( bFound ) {
650                     // scoped_node_ptr deletes the node tower if we create it before
651                     if ( !bTowerMade )
652                         scp.release();
653
654                     func( false, *node_traits::to_value_ptr(pos.pCur), val );
655                     m_Stat.onUpdateExist();
656                     return std::make_pair( true, false );
657                 }
658
659                 if ( !bInsert ) {
660                     scp.release();
661                     return std::make_pair( false, false );
662                 }
663
664                 if ( !bTowerOk ) {
665                     build_node( pNode );
666                     nHeight = pNode->height();
667                     bTowerMade = pNode->has_tower();
668                     bTowerOk = true;
669                 }
670
671                 if ( !insert_at_position( val, pNode, pos, [&func]( value_type& item ) { func( true, item, item ); })) {
672                     m_Stat.onInsertRetry();
673                     continue;
674                 }
675
676                 increase_height( nHeight );
677                 ++m_ItemCounter;
678                 scp.release();
679                 m_Stat.onAddNode( nHeight );
680                 m_Stat.onUpdateNew();
681                 return std::make_pair( true, true );
682             }
683         }
684         //@cond
685         template <typename Func>
686         CDS_DEPRECATED("ensure() is deprecated, use update()")
687         std::pair<bool, bool> ensure( value_type& val, Func func )
688         {
689             return update( val, func, true );
690         }
691         //@endcond
692
693         /// Unlinks the item \p val from the set
694         /**
695             The function searches the item \p val in the set and unlink it from the set
696             if it is found and is equal to \p val.
697
698             Difference between \p erase() and \p %unlink() functions: \p %erase() finds <i>a key</i>
699             and deletes the item found. \p %unlink() finds an item by key and deletes it
700             only if \p val is an item of that set, i.e. the pointer to item found
701             is equal to <tt> &val </tt>.
702
703             The \p disposer specified in \p Traits class template parameter is called
704             by garbage collector \p GC asynchronously.
705
706             The function returns \p true if success and \p false otherwise.
707         */
708         bool unlink( value_type& val )
709         {
710             position pos;
711
712             if ( !find_position( val, pos, key_comparator(), false )) {
713                 m_Stat.onUnlinkFailed();
714                 return false;
715             }
716
717             node_type * pDel = pos.pCur;
718             assert( key_comparator()( *node_traits::to_value_ptr( pDel ), val ) == 0 );
719
720             unsigned int nHeight = pDel->height();
721             typename gc::Guard gDel;
722             gDel.assign( node_traits::to_value_ptr(pDel));
723
724             if ( node_traits::to_value_ptr( pDel ) == &val && try_remove_at( pDel, pos, [](value_type const&) {} )) {
725                 --m_ItemCounter;
726                 m_Stat.onRemoveNode( nHeight );
727                 m_Stat.onUnlinkSuccess();
728                 return true;
729             }
730
731             m_Stat.onUnlinkFailed();
732             return false;
733         }
734
735         /// Extracts the item from the set with specified \p key
736         /** \anchor cds_intrusive_SkipListSet_hp_extract
737             The function searches an item with key equal to \p key in the set,
738             unlinks it from the set, and returns it as \p guarded_ptr object.
739             If \p key is not found the function returns an empty guarded pointer.
740
741             Note the compare functor should accept a parameter of type \p Q that can be not the same as \p value_type.
742
743             The \p disposer specified in \p Traits class template parameter is called automatically
744             by garbage collector \p GC specified in class' template parameters when returned \p guarded_ptr object
745             will be destroyed or released.
746             @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
747
748             Usage:
749             \code
750             typedef cds::intrusive::SkipListSet< cds::gc::HP, foo, my_traits >  skip_list;
751             skip_list theList;
752             // ...
753             {
754                 skip_list::guarded_ptr gp(theList.extract( 5 ));
755                 if ( gp ) {
756                     // Deal with gp
757                     // ...
758                 }
759                 // Destructor of gp releases internal HP guard
760             }
761             \endcode
762         */
763         template <typename Q>
764         guarded_ptr extract( Q const& key )
765         {
766             return extract_( key, key_comparator());
767         }
768
769         /// Extracts the item from the set with comparing functor \p pred
770         /**
771             The function is an analog of \ref cds_intrusive_SkipListSet_hp_extract "extract(Q const&)"
772             but \p pred predicate is used for key comparing.
773
774             \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
775             in any order.
776             \p pred must imply the same element order as the comparator used for building the set.
777         */
778         template <typename Q, typename Less>
779         guarded_ptr extract_with( Q const& key, Less pred )
780         {
781             CDS_UNUSED( pred );
782             return extract_( key, cds::opt::details::make_comparator_from_less<Less>());
783         }
784
785         /// Extracts an item with minimal key from the list
786         /**
787             The function searches an item with minimal key, unlinks it, and returns it as \p guarded_ptr object.
788             If the skip-list is empty the function returns an empty guarded pointer.
789
790             @note Due the concurrent nature of the list, the function extracts <i>nearly</i> minimum key.
791             It means that the function gets leftmost item and tries to unlink it.
792             During unlinking, a concurrent thread may insert an item with key less than leftmost item's key.
793             So, the function returns the item with minimum key at the moment of list traversing.
794
795             The \p disposer specified in \p Traits class template parameter is called
796             by garbage collector \p GC automatically when returned \p guarded_ptr object
797             will be destroyed or released.
798             @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
799
800             Usage:
801             \code
802             typedef cds::intrusive::SkipListSet< cds::gc::HP, foo, my_traits >  skip_list;
803             skip_list theList;
804             // ...
805             {
806                 skip_list::guarded_ptr gp(theList.extract_min());
807                 if ( gp ) {
808                     // Deal with gp
809                     //...
810                 }
811                 // Destructor of gp releases internal HP guard
812             }
813             \endcode
814         */
815         guarded_ptr extract_min()
816         {
817             return extract_min_();
818         }
819
820         /// Extracts an item with maximal key from the list
821         /**
822             The function searches an item with maximal key, unlinks it, and returns the pointer to item
823             as \p guarded_ptr object.
824             If the skip-list is empty the function returns an empty \p guarded_ptr.
825
826             @note Due the concurrent nature of the list, the function extracts <i>nearly</i> maximal key.
827             It means that the function gets rightmost item and tries to unlink it.
828             During unlinking, a concurrent thread may insert an item with key greater than rightmost item's key.
829             So, the function returns the item with maximum key at the moment of list traversing.
830
831             The \p disposer specified in \p Traits class template parameter is called
832             by garbage collector \p GC asynchronously when returned \ref guarded_ptr object
833             will be destroyed or released.
834             @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
835
836             Usage:
837             \code
838             typedef cds::intrusive::SkipListSet< cds::gc::HP, foo, my_traits > skip_list;
839             skip_list theList;
840             // ...
841             {
842                 skip_list::guarded_ptr gp( theList.extract_max( gp ));
843                 if ( gp ) {
844                     // Deal with gp
845                     //...
846                 }
847                 // Destructor of gp releases internal HP guard
848             }
849             \endcode
850         */
851         guarded_ptr extract_max()
852         {
853             return extract_max_();
854         }
855
856         /// Deletes the item from the set
857         /** \anchor cds_intrusive_SkipListSet_hp_erase
858             The function searches an item with key equal to \p key in the set,
859             unlinks it from the set, and returns \p true.
860             If the item with key equal to \p key is not found the function return \p false.
861
862             Note the compare functor should accept a parameter of type \p Q that can be not the same as \p value_type.
863         */
864         template <typename Q>
865         bool erase( Q const& key )
866         {
867             return erase_( key, key_comparator(), [](value_type const&) {} );
868         }
869
870         /// Deletes the item from the set with comparing functor \p pred
871         /**
872             The function is an analog of \ref cds_intrusive_SkipListSet_hp_erase "erase(Q const&)"
873             but \p pred predicate is used for key comparing.
874
875             \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
876             in any order.
877             \p pred must imply the same element order as the comparator used for building the set.
878         */
879         template <typename Q, typename Less>
880         bool erase_with( Q const& key, Less pred )
881         {
882             CDS_UNUSED( pred );
883             return erase_( key, cds::opt::details::make_comparator_from_less<Less>(), [](value_type const&) {} );
884         }
885
886         /// Deletes the item from the set
887         /** \anchor cds_intrusive_SkipListSet_hp_erase_func
888             The function searches an item with key equal to \p key in the set,
889             call \p f functor with item found, unlinks it from the set, and returns \p true.
890             The \ref disposer specified in \p Traits class template parameter is called
891             by garbage collector \p GC asynchronously.
892
893             The \p Func interface is
894             \code
895             struct functor {
896                 void operator()( value_type const& item );
897             };
898             \endcode
899
900             If the item with key equal to \p key is not found the function return \p false.
901
902             Note the compare functor should accept a parameter of type \p Q that can be not the same as \p value_type.
903         */
904         template <typename Q, typename Func>
905         bool erase( Q const& key, Func f )
906         {
907             return erase_( key, key_comparator(), f );
908         }
909
910         /// Deletes the item from the set with comparing functor \p pred
911         /**
912             The function is an analog of \ref cds_intrusive_SkipListSet_hp_erase_func "erase(Q const&, Func)"
913             but \p pred predicate is used for key comparing.
914
915             \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
916             in any order.
917             \p pred must imply the same element order as the comparator used for building the set.
918         */
919         template <typename Q, typename Less, typename Func>
920         bool erase_with( Q const& key, Less pred, Func f )
921         {
922             CDS_UNUSED( pred );
923             return erase_( key, cds::opt::details::make_comparator_from_less<Less>(), f );
924         }
925
926         /// Finds \p key
927         /** \anchor cds_intrusive_SkipListSet_hp_find_func
928             The function searches the item with key equal to \p key and calls the functor \p f for item found.
929             The interface of \p Func functor is:
930             \code
931             struct functor {
932                 void operator()( value_type& item, Q& key );
933             };
934             \endcode
935             where \p item is the item found, \p key is the <tt>find</tt> function argument.
936
937             The functor can change non-key fields of \p item. Note that the functor is only guarantee
938             that \p item cannot be disposed during functor is executing.
939             The functor does not serialize simultaneous access to the set \p item. If such access is
940             possible you must provide your own synchronization on item level to exclude unsafe item modifications.
941
942             Note the compare functor specified for class \p Traits template parameter
943             should accept a parameter of type \p Q that can be not the same as \p value_type.
944
945             The function returns \p true if \p key is found, \p false otherwise.
946         */
947         template <typename Q, typename Func>
948         bool find( Q& key, Func f )
949         {
950             return find_with_( key, key_comparator(), f );
951         }
952         //@cond
953         template <typename Q, typename Func>
954         bool find( Q const& key, Func f )
955         {
956             return find_with_( key, key_comparator(), f );
957         }
958         //@endcond
959
960         /// Finds the key \p key with \p pred predicate for comparing
961         /**
962             The function is an analog of \ref cds_intrusive_SkipListSet_hp_find_func "find(Q&, Func)"
963             but \p pred is used for key compare.
964
965             \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
966             in any order.
967             \p pred must imply the same element order as the comparator used for building the set.
968         */
969         template <typename Q, typename Less, typename Func>
970         bool find_with( Q& key, Less pred, Func f )
971         {
972             CDS_UNUSED( pred );
973             return find_with_( key, cds::opt::details::make_comparator_from_less<Less>(), f );
974         }
975         //@cond
976         template <typename Q, typename Less, typename Func>
977         bool find_with( Q const& key, Less pred, Func f )
978         {
979             CDS_UNUSED( pred );
980             return find_with_( key, cds::opt::details::make_comparator_from_less<Less>(), f );
981         }
982         //@endcond
983
984         /// Checks whether the set contains \p key
985         /**
986             The function searches the item with key equal to \p key
987             and returns \p true if it is found, and \p false otherwise.
988         */
989         template <typename Q>
990         bool contains( Q const& key )
991         {
992             return find_with_( key, key_comparator(), [](value_type& , Q const& ) {} );
993         }
994         //@cond
995         template <typename Q>
996         CDS_DEPRECATED("deprecated, use contains()")
997         bool find( Q const& key )
998         {
999             return contains( key );
1000         }
1001         //@endcond
1002
1003         /// Checks whether the set contains \p key using \p pred predicate for searching
1004         /**
1005             The function is similar to <tt>contains( key )</tt> but \p pred is used for key comparing.
1006             \p Less functor has the interface like \p std::less.
1007             \p Less must imply the same element order as the comparator used for building the set.
1008         */
1009         template <typename Q, typename Less>
1010         bool contains( Q const& key, Less pred )
1011         {
1012             CDS_UNUSED( pred );
1013             return find_with_( key, cds::opt::details::make_comparator_from_less<Less>(), [](value_type& , Q const& ) {} );
1014         }
1015         //@cond
1016         template <typename Q, typename Less>
1017         CDS_DEPRECATED("deprecated, use contains()")
1018         bool find_with( Q const& key, Less pred )
1019         {
1020             return contains( key, pred );
1021         }
1022         //@endcond
1023
1024         /// Finds \p key and return the item found
1025         /** \anchor cds_intrusive_SkipListSet_hp_get
1026             The function searches the item with key equal to \p key
1027             and returns the pointer to the item found as \p guarded_ptr.
1028             If \p key is not found the function returns an empt guarded pointer.
1029
1030             The \p disposer specified in \p Traits class template parameter is called
1031             by garbage collector \p GC asynchronously when returned \ref guarded_ptr object
1032             will be destroyed or released.
1033             @note Each \p guarded_ptr object uses one GC's guard which can be limited resource.
1034
1035             Usage:
1036             \code
1037             typedef cds::intrusive::SkipListSet< cds::gc::HP, foo, my_traits >  skip_list;
1038             skip_list theList;
1039             // ...
1040             {
1041                 skip_list::guarded_ptr gp(theList.get( 5 ));
1042                 if ( gp ) {
1043                     // Deal with gp
1044                     //...
1045                 }
1046                 // Destructor of guarded_ptr releases internal HP guard
1047             }
1048             \endcode
1049
1050             Note the compare functor specified for class \p Traits template parameter
1051             should accept a parameter of type \p Q that can be not the same as \p value_type.
1052         */
1053         template <typename Q>
1054         guarded_ptr get( Q const& key )
1055         {
1056             return get_with_( key, key_comparator());
1057         }
1058
1059         /// Finds \p key and return the item found
1060         /**
1061             The function is an analog of \ref cds_intrusive_SkipListSet_hp_get "get( Q const&)"
1062             but \p pred is used for comparing the keys.
1063
1064             \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
1065             in any order.
1066             \p pred must imply the same element order as the comparator used for building the set.
1067         */
1068         template <typename Q, typename Less>
1069         guarded_ptr get_with( Q const& key, Less pred )
1070         {
1071             CDS_UNUSED( pred );
1072             return get_with_( key, cds::opt::details::make_comparator_from_less<Less>());
1073         }
1074
1075         /// Returns item count in the set
1076         /**
1077             The value returned depends on item counter type provided by \p Traits template parameter.
1078             If it is \p atomicity::empty_item_counter this function always returns 0.
1079             Therefore, the function is not suitable for checking the set emptiness, use \p empty()
1080             for this purpose.
1081         */
1082         size_t size() const
1083         {
1084             return m_ItemCounter;
1085         }
1086
1087         /// Checks if the set is empty
1088         bool empty() const
1089         {
1090             return m_Head.head()->next( 0 ).load( memory_model::memory_order_relaxed ) == nullptr;
1091         }
1092
1093         /// Clears the set (not atomic)
1094         /**
1095             The function unlink all items from the set.
1096             The function is not atomic, i.e., in multi-threaded environment with parallel insertions
1097             this sequence
1098             \code
1099             set.clear();
1100             assert( set.empty());
1101             \endcode
1102             the assertion could be raised.
1103
1104             For each item the \ref disposer will be called after unlinking.
1105         */
1106         void clear()
1107         {
1108             while ( extract_min_());
1109         }
1110
1111         /// Returns maximum height of skip-list. The max height is a constant for each object and does not exceed 32.
1112         static CDS_CONSTEXPR unsigned int max_height() CDS_NOEXCEPT
1113         {
1114             return c_nMaxHeight;
1115         }
1116
1117         /// Returns const reference to internal statistics
1118         stat const& statistics() const
1119         {
1120             return m_Stat;
1121         }
1122
1123     protected:
1124         //@cond
1125         unsigned int random_level()
1126         {
1127             // Random generator produces a number from range [0..31]
1128             // We need a number from range [1..32]
1129             return m_RandomLevelGen() + 1;
1130         }
1131
1132         template <typename Q>
1133         node_type * build_node( Q v )
1134         {
1135             return node_builder::make_tower( v, m_RandomLevelGen );
1136         }
1137
1138         static value_type * gc_protect( marked_node_ptr p )
1139         {
1140             return node_traits::to_value_ptr( p.ptr() );
1141         }
1142
1143         static void dispose_node( value_type * pVal )
1144         {
1145             assert( pVal != nullptr );
1146             typename node_builder::node_disposer()( node_traits::to_node_ptr( pVal ) );
1147             disposer()( pVal );
1148         }
1149
1150         void help_remove( int nLevel, node_type* pPred, marked_node_ptr pCur, marked_node_ptr pSucc )
1151         {
1152             marked_node_ptr p( pCur.ptr() );
1153             if ( pPred->next( nLevel ).compare_exchange_strong( p, marked_node_ptr( pSucc.ptr()),
1154                 memory_model::memory_order_acquire, atomics::memory_order_relaxed ) )
1155             {
1156                 if ( nLevel == 0 ) {
1157                     gc::retire( node_traits::to_value_ptr( pCur.ptr() ), dispose_node );
1158                     m_Stat.onEraseWhileFind();
1159                 }
1160             }
1161         }
1162
1163         template <typename Q, typename Compare >
1164         bool find_position( Q const& val, position& pos, Compare cmp, bool bStopIfFound )
1165         {
1166             node_type * pPred;
1167             marked_node_ptr pSucc;
1168             marked_node_ptr pCur;
1169
1170             // Hazard pointer array:
1171             //  pPred: [nLevel * 2]
1172             //  pSucc: [nLevel * 2 + 1]
1173
1174         retry:
1175             pPred = m_Head.head();
1176             int nCmp = 1;
1177
1178             for ( int nLevel = static_cast<int>( c_nMaxHeight - 1 ); nLevel >= 0; --nLevel ) {
1179                 pos.guards.assign( nLevel * 2, node_traits::to_value_ptr( pPred ) );
1180                 while ( true ) {
1181                     pCur = pos.guards.protect( nLevel * 2 + 1, pPred->next( nLevel ), gc_protect );
1182                     if ( pCur.bits() ) {
1183                         // pCur.bits() means that pPred is logically deleted
1184                         goto retry;
1185                     }
1186
1187                     if ( pCur.ptr() == nullptr ) {
1188                         // end of list at level nLevel - goto next level
1189                         break;
1190                     }
1191
1192                     // pSucc contains deletion mark for pCur
1193                     pSucc = pCur->next( nLevel ).load( memory_model::memory_order_acquire );
1194
1195                     if ( pPred->next( nLevel ).load( memory_model::memory_order_acquire ).all() != pCur.ptr() )
1196                         goto retry;
1197
1198                     if ( pSucc.bits() ) {
1199                         // pCur is marked, i.e. logically deleted
1200                         // try to help deleting pCur if pSucc is not being deleted
1201                         help_remove( nLevel, pPred, pCur, pSucc );
1202                         goto retry;
1203                     }
1204                     else {
1205                         nCmp = cmp( *node_traits::to_value_ptr( pCur.ptr() ), val );
1206                         if ( nCmp < 0 ) {
1207                             pPred = pCur.ptr();
1208                             pos.guards.copy( nLevel * 2, nLevel * 2 + 1 );   // pPrev guard := cur guard
1209                         }
1210                         else if ( nCmp == 0 && bStopIfFound )
1211                             goto found;
1212                         else
1213                             break;
1214                     }
1215                 }
1216
1217                 // Next level
1218                 pos.pPrev[nLevel] = pPred;
1219                 pos.pSucc[nLevel] = pCur.ptr();
1220             }
1221
1222             if ( nCmp != 0 )
1223                 return false;
1224
1225         found:
1226             pos.pCur = pCur.ptr();
1227             return pCur.ptr() && nCmp == 0;
1228         }
1229
1230         bool find_min_position( position& pos )
1231         {
1232             node_type * pPred;
1233             marked_node_ptr pSucc;
1234             marked_node_ptr pCur;
1235
1236             // Hazard pointer array:
1237             //  pPred: [nLevel * 2]
1238             //  pSucc: [nLevel * 2 + 1]
1239
1240         retry:
1241             pPred = m_Head.head();
1242
1243             for ( int nLevel = static_cast<int>( c_nMaxHeight - 1 ); nLevel >= 0; --nLevel ) {
1244                 pos.guards.assign( nLevel * 2, node_traits::to_value_ptr( pPred ) );
1245                 pCur = pos.guards.protect( nLevel * 2 + 1, pPred->next( nLevel ), gc_protect );
1246
1247                 // pCur.bits() means that pPred is logically deleted
1248                 // head cannot be deleted
1249                 assert( pCur.bits() == 0 );
1250
1251                 if ( pCur.ptr() ) {
1252
1253                     // pSucc contains deletion mark for pCur
1254                     pSucc = pCur->next( nLevel ).load( memory_model::memory_order_acquire );
1255
1256                     if ( pPred->next( nLevel ).load( memory_model::memory_order_acquire ).all() != pCur.ptr() )
1257                         goto retry;
1258
1259                     if ( pSucc.bits() ) {
1260                         // pCur is marked, i.e. logically deleted.
1261                         // try to help deleting pCur if pSucc is not being deleted
1262                         help_remove( nLevel, pPred, pCur, pSucc );
1263                         goto retry;
1264                     }
1265                 }
1266
1267                 // Next level
1268                 pos.pPrev[nLevel] = pPred;
1269                 pos.pSucc[nLevel] = pCur.ptr();
1270             }
1271
1272             return ( pos.pCur = pCur.ptr() ) != nullptr;
1273         }
1274
1275         bool find_max_position( position& pos )
1276         {
1277             node_type * pPred;
1278             marked_node_ptr pSucc;
1279             marked_node_ptr pCur;
1280
1281             // Hazard pointer array:
1282             //  pPred: [nLevel * 2]
1283             //  pSucc: [nLevel * 2 + 1]
1284
1285         retry:
1286             pPred = m_Head.head();
1287
1288             for ( int nLevel = static_cast<int>( c_nMaxHeight - 1 ); nLevel >= 0; --nLevel ) {
1289                 pos.guards.assign( nLevel * 2, node_traits::to_value_ptr( pPred ) );
1290                 while ( true ) {
1291                     pCur = pos.guards.protect( nLevel * 2 + 1, pPred->next( nLevel ), gc_protect );
1292                     if ( pCur.bits() ) {
1293                         // pCur.bits() means that pPred is logically deleted
1294                         goto retry;
1295                     }
1296
1297                     if ( pCur.ptr() == nullptr ) {
1298                         // end of the list at level nLevel - goto next level
1299                         break;
1300                     }
1301
1302                     // pSucc contains deletion mark for pCur
1303                     pSucc = pCur->next( nLevel ).load( memory_model::memory_order_acquire );
1304
1305                     if ( pPred->next( nLevel ).load( memory_model::memory_order_acquire ).all() != pCur.ptr() )
1306                         goto retry;
1307
1308                     if ( pSucc.bits() ) {
1309                         // pCur is marked, i.e. logically deleted.
1310                         // try to help deleting pCur if pSucc is not being deleted
1311                         help_remove( nLevel, pPred, pCur, pSucc );
1312                         goto retry;
1313                     }
1314                     else {
1315                         if ( !pSucc.ptr() )
1316                             break;
1317
1318                         pPred = pCur.ptr();
1319                         pos.guards.copy( nLevel * 2, nLevel * 2 + 1 ); 
1320                     }
1321                 }
1322
1323                 // Next level
1324                 pos.pPrev[nLevel] = pPred;
1325                 pos.pSucc[nLevel] = pCur.ptr();
1326             }
1327
1328             return ( pos.pCur = pCur.ptr() ) != nullptr;
1329         }
1330
1331         template <typename Func>
1332         bool insert_at_position( value_type& val, node_type * pNode, position& pos, Func f )
1333         {
1334             unsigned int nHeight = pNode->height();
1335
1336             for ( unsigned int nLevel = 1; nLevel < nHeight; ++nLevel )
1337                 pNode->next( nLevel ).store( marked_node_ptr(), memory_model::memory_order_relaxed );
1338
1339             // Insert at level 0
1340             {
1341                 node_type* succ = pos.pSucc[0];
1342
1343                 marked_node_ptr p( succ );
1344                 pNode->next( 0 ).store( p, memory_model::memory_order_release );
1345                 if ( !pos.pPrev[0]->next( 0 ).compare_exchange_strong( p, marked_node_ptr( pNode ), memory_model::memory_order_release, atomics::memory_order_relaxed ))
1346                     return false;
1347
1348                 f( val );
1349             }
1350
1351             // Insert at level 1..max
1352             for ( unsigned int nLevel = 1; nLevel < nHeight; ++nLevel ) {
1353                 marked_node_ptr p;
1354                 while ( true ) {
1355                     marked_node_ptr q( pos.pSucc[nLevel] );
1356
1357                     if ( !pNode->next( nLevel ).compare_exchange_strong( p, q, memory_model::memory_order_release, atomics::memory_order_relaxed )) {
1358                         // pNode has been marked as removed while we are inserting it
1359                         // Stop inserting
1360                         assert( p.bits() );
1361                         m_Stat.onLogicDeleteWhileInsert();
1362                         return true;
1363                     }
1364
1365                     p = q;
1366                     bool const result = pos.pPrev[nLevel]->next( nLevel ).compare_exchange_strong( q, marked_node_ptr( pNode ),
1367                         memory_model::memory_order_release, atomics::memory_order_relaxed );
1368                     if ( result )
1369                         break;
1370
1371                     // Renew insert position
1372                     m_Stat.onRenewInsertPosition();
1373                     if ( !find_position( val, pos, key_comparator(), false ) ) {
1374                         // The node has been deleted while we are inserting it
1375                         m_Stat.onNotFoundWhileInsert();
1376                         return true;
1377                     }
1378                 }
1379             }
1380             return true;
1381         }
1382
1383         template <typename Func>
1384         bool try_remove_at( node_type * pDel, position& pos, Func f )
1385         {
1386             assert( pDel != nullptr );
1387
1388             marked_node_ptr pSucc;
1389
1390             // logical deletion (marking)
1391             for ( unsigned int nLevel = pDel->height() - 1; nLevel > 0; --nLevel ) {
1392                 while ( true ) {
1393                     pSucc = pDel->next( nLevel );
1394                     if ( pSucc.bits() || pDel->next( nLevel ).compare_exchange_weak( pSucc, pSucc | 1,
1395                         memory_model::memory_order_release, atomics::memory_order_relaxed ) )
1396                     {
1397                         break;
1398                     }
1399                 }
1400             }
1401
1402             while ( true ) {
1403                 marked_node_ptr p( pDel->next( 0 ).load( memory_model::memory_order_relaxed ).ptr() );
1404                 if ( pDel->next( 0 ).compare_exchange_strong( p, p | 1, memory_model::memory_order_release, atomics::memory_order_relaxed ) )
1405                 {
1406                     f( *node_traits::to_value_ptr( pDel ) );
1407
1408                     // Physical deletion
1409                     // try fast erase
1410                     p = pDel;
1411                     for ( int nLevel = static_cast<int>( pDel->height() - 1 ); nLevel >= 0; --nLevel ) {
1412                         pSucc = pDel->next( nLevel ).load( memory_model::memory_order_relaxed );
1413                         if ( !pos.pPrev[nLevel]->next( nLevel ).compare_exchange_strong( p, marked_node_ptr( pSucc.ptr() ),
1414                             memory_model::memory_order_acquire, atomics::memory_order_relaxed ) )
1415                         {
1416                             // Make slow erase
1417                             find_position( *node_traits::to_value_ptr( pDel ), pos, key_comparator(), false );
1418                             m_Stat.onSlowErase();
1419                             return true;
1420                         }
1421                     }
1422
1423                     // Fast erasing success
1424                     gc::retire( node_traits::to_value_ptr( pDel ), dispose_node );
1425                     m_Stat.onFastErase();
1426                     return true;
1427                 }
1428                 else {
1429                     if ( p.bits() ) {
1430                         // Another thread is deleting pDel right now
1431                         return false;
1432                     }
1433                 }
1434                 m_Stat.onEraseRetry();
1435             }
1436         }
1437
1438         enum finsd_fastpath_result {
1439             find_fastpath_found,
1440             find_fastpath_not_found,
1441             find_fastpath_abort
1442         };
1443         template <typename Q, typename Compare, typename Func>
1444         finsd_fastpath_result find_fastpath( Q& val, Compare cmp, Func f )
1445         {
1446             node_type * pPred;
1447             typename gc::template GuardArray<2>  guards;
1448             marked_node_ptr pCur;
1449             marked_node_ptr pNull;
1450
1451             back_off bkoff;
1452
1453             pPred = m_Head.head();
1454             for ( int nLevel = static_cast<int>( m_nHeight.load( memory_model::memory_order_relaxed ) - 1 ); nLevel >= 0; --nLevel ) {
1455                 pCur = guards.protect( 1, pPred->next( nLevel ), gc_protect );
1456                 if ( pCur == pNull )
1457                     continue;
1458
1459                 while ( pCur != pNull ) {
1460                     if ( pCur.bits() ) {
1461                         unsigned int nAttempt = 0;
1462                         bkoff.reset();
1463                         while ( pCur.bits() && nAttempt++ < 16 ) {
1464                             bkoff();
1465                             pCur = guards.protect( 1, pPred->next( nLevel ), gc_protect );
1466                         }
1467
1468                         if ( pCur.bits() ) {
1469                             // Maybe, we are on deleted node sequence
1470                             // Abort searching, try slow-path
1471                             return find_fastpath_abort;
1472                         }
1473                     }
1474
1475                     if ( pCur.ptr() ) {
1476                         int nCmp = cmp( *node_traits::to_value_ptr( pCur.ptr() ), val );
1477                         if ( nCmp < 0 ) {
1478                             guards.copy( 0, 1 );
1479                             pPred = pCur.ptr();
1480                             pCur = guards.protect( 1, pCur->next( nLevel ), gc_protect );
1481                         }
1482                         else if ( nCmp == 0 ) {
1483                             // found
1484                             f( *node_traits::to_value_ptr( pCur.ptr() ), val );
1485                             return find_fastpath_found;
1486                         }
1487                         else // pCur > val - go down
1488                             break;
1489                     }
1490                 }
1491             }
1492
1493             return find_fastpath_not_found;
1494         }
1495
1496         template <typename Q, typename Compare, typename Func>
1497         bool find_slowpath( Q& val, Compare cmp, Func f )
1498         {
1499             position pos;
1500             if ( find_position( val, pos, cmp, true ) ) {
1501                 assert( cmp( *node_traits::to_value_ptr( pos.pCur ), val ) == 0 );
1502
1503                 f( *node_traits::to_value_ptr( pos.pCur ), val );
1504                 return true;
1505             }
1506             else
1507                 return false;
1508         }
1509
1510         template <typename Q, typename Compare, typename Func>
1511         bool find_with_( Q& val, Compare cmp, Func f )
1512         {
1513             switch ( find_fastpath( val, cmp, f ) ) {
1514             case find_fastpath_found:
1515                 m_Stat.onFindFastSuccess();
1516                 return true;
1517             case find_fastpath_not_found:
1518                 m_Stat.onFindFastFailed();
1519                 return false;
1520             default:
1521                 break;
1522             }
1523
1524             if ( find_slowpath( val, cmp, f ) ) {
1525                 m_Stat.onFindSlowSuccess();
1526                 return true;
1527             }
1528
1529             m_Stat.onFindSlowFailed();
1530             return false;
1531         }
1532
1533         template <typename Q, typename Compare>
1534         guarded_ptr get_with_( Q const& val, Compare cmp )
1535         {
1536             guarded_ptr gp;
1537             if ( find_with_( val, cmp, [&gp]( value_type& found, Q const& ) { gp.reset( &found ); } ) )
1538                 return gp;
1539             return guarded_ptr();
1540         }
1541
1542         template <typename Q, typename Compare, typename Func>
1543         bool erase_( Q const& val, Compare cmp, Func f )
1544         {
1545             position pos;
1546
1547             if ( !find_position( val, pos, cmp, false ) ) {
1548                 m_Stat.onEraseFailed();
1549                 return false;
1550             }
1551
1552             node_type * pDel = pos.pCur;
1553             typename gc::Guard gDel;
1554             gDel.assign( node_traits::to_value_ptr( pDel ) );
1555             assert( cmp( *node_traits::to_value_ptr( pDel ), val ) == 0 );
1556
1557             unsigned int nHeight = pDel->height();
1558             if ( try_remove_at( pDel, pos, f ) ) {
1559                 --m_ItemCounter;
1560                 m_Stat.onRemoveNode( nHeight );
1561                 m_Stat.onEraseSuccess();
1562                 return true;
1563             }
1564
1565             m_Stat.onEraseFailed();
1566             return false;
1567         }
1568
1569         template <typename Q, typename Compare>
1570         guarded_ptr extract_( Q const& val, Compare cmp )
1571         {
1572             position pos;
1573
1574             guarded_ptr gp;
1575             for (;;) {
1576                 if ( !find_position( val, pos, cmp, false ) ) {
1577                     m_Stat.onExtractFailed();
1578                     return guarded_ptr();
1579                 }
1580
1581                 node_type * pDel = pos.pCur;
1582                 gp.reset( node_traits::to_value_ptr( pDel ) );
1583                 assert( cmp( *node_traits::to_value_ptr( pDel ), val ) == 0 );
1584
1585                 unsigned int nHeight = pDel->height();
1586                 if ( try_remove_at( pDel, pos, []( value_type const& ) {} ) ) {
1587                     --m_ItemCounter;
1588                     m_Stat.onRemoveNode( nHeight );
1589                     m_Stat.onExtractSuccess();
1590                     return gp;
1591                 }
1592                 m_Stat.onExtractRetry();
1593             }
1594         }
1595
1596         guarded_ptr extract_min_()
1597         {
1598             position pos;
1599
1600             guarded_ptr gp;
1601             for ( ;;) {
1602                 if ( !find_min_position( pos ) ) {
1603                     // The list is empty
1604                     m_Stat.onExtractMinFailed();
1605                     return guarded_ptr();
1606                 }
1607
1608                 node_type * pDel = pos.pCur;
1609
1610                 unsigned int nHeight = pDel->height();
1611                 gp.reset( node_traits::to_value_ptr( pDel ) );
1612
1613                 if ( try_remove_at( pDel, pos, []( value_type const& ) {} ) ) {
1614                     --m_ItemCounter;
1615                     m_Stat.onRemoveNode( nHeight );
1616                     m_Stat.onExtractMinSuccess();
1617                     return gp;
1618                 }
1619
1620                 m_Stat.onExtractMinRetry();
1621             }
1622         }
1623
1624         guarded_ptr extract_max_()
1625         {
1626             position pos;
1627
1628             guarded_ptr gp;
1629             for ( ;;) {
1630                 if ( !find_max_position( pos ) ) {
1631                     // The list is empty
1632                     m_Stat.onExtractMaxFailed();
1633                     return guarded_ptr();
1634                 }
1635
1636                 node_type * pDel = pos.pCur;
1637
1638                 unsigned int nHeight = pDel->height();
1639                 gp.reset( node_traits::to_value_ptr( pDel ) );
1640
1641                 if ( try_remove_at( pDel, pos, []( value_type const& ) {} ) ) {
1642                     --m_ItemCounter;
1643                     m_Stat.onRemoveNode( nHeight );
1644                     m_Stat.onExtractMaxSuccess();
1645                     return gp;
1646                 }
1647
1648                 m_Stat.onExtractMaxRetry();
1649             }
1650         }
1651
1652         void increase_height( unsigned int nHeight )
1653         {
1654             unsigned int nCur = m_nHeight.load( memory_model::memory_order_relaxed );
1655             if ( nCur < nHeight )
1656                 m_nHeight.compare_exchange_strong( nCur, nHeight, memory_model::memory_order_release, atomics::memory_order_relaxed );
1657         }
1658         //@endcond
1659
1660     private:
1661         //@cond
1662         skip_list::details::head_node< node_type > m_Head;   ///< head tower (max height)
1663
1664         item_counter                m_ItemCounter;    ///< item counter
1665         random_level_generator      m_RandomLevelGen; ///< random level generator instance
1666         atomics::atomic<unsigned int> m_nHeight;      ///< estimated high level
1667         mutable stat                m_Stat;           ///< internal statistics
1668         //@endcond
1669     };
1670
1671 }} // namespace cds::intrusive
1672
1673
1674 #endif // #ifndef CDSLIB_INTRUSIVE_IMPL_SKIP_LIST_H