4f7d1eaf3b9e03072ac54dae47f460c0bda2d5ef
[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(); // nHeight > 1 && pNode->get_tower() != nullptr;
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         template <typename Q, typename Compare >
1151         bool find_position( Q const& val, position& pos, Compare cmp, bool bStopIfFound )
1152         {
1153             node_type * pPred;
1154             marked_node_ptr pSucc;
1155             marked_node_ptr pCur;
1156
1157             // Hazard pointer array:
1158             //  pPred: [nLevel * 2]
1159             //  pSucc: [nLevel * 2 + 1]
1160
1161         retry:
1162             pPred = m_Head.head();
1163             int nCmp = 1;
1164
1165             for ( int nLevel = static_cast<int>( c_nMaxHeight - 1 ); nLevel >= 0; --nLevel ) {
1166                 pos.guards.assign( nLevel * 2, node_traits::to_value_ptr( pPred ) );
1167                 while ( true ) {
1168                     pCur = pos.guards.protect( nLevel * 2 + 1, pPred->next( nLevel ), gc_protect );
1169                     if ( pCur.bits() ) {
1170                         // pCur.bits() means that pPred is logically deleted
1171                         goto retry;
1172                     }
1173
1174                     if ( pCur.ptr() == nullptr ) {
1175                         // end of list at level nLevel - goto next level
1176                         break;
1177                     }
1178
1179                     // pSucc contains deletion mark for pCur
1180                     pSucc = pCur->next( nLevel ).load( memory_model::memory_order_acquire );
1181
1182                     if ( pPred->next( nLevel ).load( memory_model::memory_order_acquire ).all() != pCur.ptr() )
1183                         goto retry;
1184
1185                     if ( pSucc.bits() ) {
1186                         // pCur is marked, i.e. logically deleted.
1187                         marked_node_ptr p( pCur.ptr() );
1188                         if ( pPred->next( nLevel ).compare_exchange_strong( p, marked_node_ptr( pSucc.ptr() ),
1189                             memory_model::memory_order_acquire, atomics::memory_order_relaxed ) )
1190                         {
1191                             if ( nLevel == 0 ) {
1192                                 gc::retire( node_traits::to_value_ptr( pCur.ptr() ), dispose_node );
1193                                 m_Stat.onEraseWhileFind();
1194                             }
1195                         }
1196                         goto retry;
1197                     }
1198                     else {
1199                         nCmp = cmp( *node_traits::to_value_ptr( pCur.ptr() ), val );
1200                         if ( nCmp < 0 ) {
1201                             pPred = pCur.ptr();
1202                             pos.guards.copy( nLevel * 2, nLevel * 2 + 1 );   // pPrev guard := cur guard
1203                         }
1204                         else if ( nCmp == 0 && bStopIfFound )
1205                             goto found;
1206                         else
1207                             break;
1208                     }
1209                 }
1210
1211                 // Next level
1212                 pos.pPrev[nLevel] = pPred;
1213                 pos.pSucc[nLevel] = pCur.ptr();
1214             }
1215
1216             if ( nCmp != 0 )
1217                 return false;
1218
1219         found:
1220             pos.pCur = pCur.ptr();
1221             return pCur.ptr() && nCmp == 0;
1222         }
1223
1224         bool find_min_position( position& pos )
1225         {
1226             node_type * pPred;
1227             marked_node_ptr pSucc;
1228             marked_node_ptr pCur;
1229
1230             // Hazard pointer array:
1231             //  pPred: [nLevel * 2]
1232             //  pSucc: [nLevel * 2 + 1]
1233
1234         retry:
1235             pPred = m_Head.head();
1236
1237             for ( int nLevel = static_cast<int>( c_nMaxHeight - 1 ); nLevel >= 0; --nLevel ) {
1238                 pos.guards.assign( nLevel * 2, node_traits::to_value_ptr( pPred ) );
1239                 pCur = pos.guards.protect( nLevel * 2 + 1, pPred->next( nLevel ), gc_protect );
1240
1241                 // pCur.bits() means that pPred is logically deleted
1242                 // head cannot be deleted
1243                 assert( pCur.bits() == 0 );
1244
1245                 if ( pCur.ptr() ) {
1246
1247                     // pSucc contains deletion mark for pCur
1248                     pSucc = pCur->next( nLevel ).load( memory_model::memory_order_acquire );
1249
1250                     if ( pPred->next( nLevel ).load( memory_model::memory_order_acquire ).all() != pCur.ptr() )
1251                         goto retry;
1252
1253                     if ( pSucc.bits() ) {
1254                         // pCur is marked, i.e. logically deleted.
1255                         marked_node_ptr p( pCur.ptr() );
1256                         if ( pPred->next( nLevel ).compare_exchange_strong( p, marked_node_ptr( pSucc.ptr() ),
1257                             memory_model::memory_order_acquire, atomics::memory_order_relaxed ) )
1258                         {
1259                             if ( nLevel == 0 ) {
1260                                 gc::retire( node_traits::to_value_ptr( pCur.ptr() ), dispose_node );
1261                                 m_Stat.onEraseWhileFind();
1262                             }
1263                         }
1264                         goto retry;
1265                     }
1266                 }
1267
1268                 // Next level
1269                 pos.pPrev[nLevel] = pPred;
1270                 pos.pSucc[nLevel] = pCur.ptr();
1271             }
1272
1273             return ( pos.pCur = pCur.ptr() ) != nullptr;
1274         }
1275
1276         bool find_max_position( position& pos )
1277         {
1278             node_type * pPred;
1279             marked_node_ptr pSucc;
1280             marked_node_ptr pCur;
1281
1282             // Hazard pointer array:
1283             //  pPred: [nLevel * 2]
1284             //  pSucc: [nLevel * 2 + 1]
1285
1286         retry:
1287             pPred = m_Head.head();
1288
1289             for ( int nLevel = static_cast<int>( c_nMaxHeight - 1 ); nLevel >= 0; --nLevel ) {
1290                 pos.guards.assign( nLevel * 2, node_traits::to_value_ptr( pPred ) );
1291                 while ( true ) {
1292                     pCur = pos.guards.protect( nLevel * 2 + 1, pPred->next( nLevel ), gc_protect );
1293                     if ( pCur.bits() ) {
1294                         // pCur.bits() means that pPred is logically deleted
1295                         goto retry;
1296                     }
1297
1298                     if ( pCur.ptr() == nullptr ) {
1299                         // end of the list at level nLevel - goto next level
1300                         break;
1301                     }
1302
1303                     // pSucc contains deletion mark for pCur
1304                     pSucc = pCur->next( nLevel ).load( memory_model::memory_order_acquire );
1305
1306                     if ( pPred->next( nLevel ).load( memory_model::memory_order_acquire ).all() != pCur.ptr() )
1307                         goto retry;
1308
1309                     if ( pSucc.bits() ) {
1310                         // pCur is marked, i.e. logically deleted.
1311                         marked_node_ptr p( pCur.ptr() );
1312                         if ( pPred->next( nLevel ).compare_exchange_strong( p, marked_node_ptr( pSucc.ptr() ),
1313                             memory_model::memory_order_acquire, atomics::memory_order_relaxed ) )
1314                         {
1315                             if ( nLevel == 0 ) {
1316                                 gc::retire( node_traits::to_value_ptr( pCur.ptr() ), dispose_node );
1317                                 m_Stat.onEraseWhileFind();
1318                             }
1319                         }
1320                         goto retry;
1321                     }
1322                     else {
1323                         if ( !pSucc.ptr() )
1324                             break;
1325
1326                         pPred = pCur.ptr();
1327                         pos.guards.copy( nLevel * 2, nLevel * 2 + 1 ); 
1328                     }
1329                 }
1330
1331                 // Next level
1332                 pos.pPrev[nLevel] = pPred;
1333                 pos.pSucc[nLevel] = pCur.ptr();
1334             }
1335
1336             return ( pos.pCur = pCur.ptr() ) != nullptr;
1337         }
1338
1339         template <typename Func>
1340         bool insert_at_position( value_type& val, node_type * pNode, position& pos, Func f )
1341         {
1342             unsigned int nHeight = pNode->height();
1343
1344             for ( unsigned int nLevel = 1; nLevel < nHeight; ++nLevel )
1345                 pNode->next( nLevel ).store( marked_node_ptr(), memory_model::memory_order_relaxed );
1346
1347             // Insert at level 0
1348             {
1349                 marked_node_ptr p( pos.pSucc[0] );
1350                 pNode->next( 0 ).store( p, memory_model::memory_order_release );
1351                 if ( !pos.pPrev[0]->next( 0 ).compare_exchange_strong( p, marked_node_ptr( pNode ), memory_model::memory_order_release, atomics::memory_order_relaxed ) )
1352                     return false;
1353
1354                 f( val );
1355             }
1356
1357             // Insert at level 1..max
1358             for ( unsigned int nLevel = 1; nLevel < nHeight; ++nLevel ) {
1359                 marked_node_ptr p;
1360                 while ( true ) {
1361                     marked_node_ptr q( pos.pSucc[nLevel] );
1362                     if ( !pNode->next( nLevel ).compare_exchange_strong( p, q, memory_model::memory_order_release, atomics::memory_order_relaxed ) ) {
1363                         // pNode has been marked as removed while we are inserting it
1364                         // Stop inserting
1365                         assert( p.bits() );
1366                         m_Stat.onLogicDeleteWhileInsert();
1367                         return true;
1368                     }
1369                     p = q;
1370                     if ( pos.pPrev[nLevel]->next( nLevel ).compare_exchange_strong( q, marked_node_ptr( pNode ), memory_model::memory_order_release, atomics::memory_order_relaxed ) )
1371                         break;
1372
1373                     // Renew insert position
1374                     m_Stat.onRenewInsertPosition();
1375                     if ( !find_position( val, pos, key_comparator(), false ) ) {
1376                         // The node has been deleted while we are inserting it
1377                         m_Stat.onNotFoundWhileInsert();
1378                         return true;
1379                     }
1380                 }
1381             }
1382             return true;
1383         }
1384
1385         template <typename Func>
1386         bool try_remove_at( node_type * pDel, position& pos, Func f )
1387         {
1388             assert( pDel != nullptr );
1389
1390             marked_node_ptr pSucc;
1391
1392             // logical deletion (marking)
1393             for ( unsigned int nLevel = pDel->height() - 1; nLevel > 0; --nLevel ) {
1394                 while ( true ) {
1395                     pSucc = pDel->next( nLevel );
1396                     if ( pSucc.bits() || pDel->next( nLevel ).compare_exchange_weak( pSucc, pSucc | 1,
1397                         memory_model::memory_order_release, atomics::memory_order_relaxed ) )
1398                     {
1399                         break;
1400                     }
1401                 }
1402             }
1403
1404             while ( true ) {
1405                 marked_node_ptr p( pDel->next( 0 ).load( memory_model::memory_order_relaxed ).ptr() );
1406                 if ( pDel->next( 0 ).compare_exchange_strong( p, p | 1, memory_model::memory_order_release, atomics::memory_order_relaxed ) )
1407                 {
1408                     f( *node_traits::to_value_ptr( pDel ) );
1409
1410                     // Physical deletion
1411                     // try fast erase
1412                     p = pDel;
1413                     for ( int nLevel = static_cast<int>( pDel->height() - 1 ); nLevel >= 0; --nLevel ) {
1414                         pSucc = pDel->next( nLevel ).load( memory_model::memory_order_relaxed );
1415                         if ( !pos.pPrev[nLevel]->next( nLevel ).compare_exchange_strong( p, marked_node_ptr( pSucc.ptr() ),
1416                             memory_model::memory_order_acquire, atomics::memory_order_relaxed ) )
1417                         {
1418                             // Make slow erase
1419                             find_position( *node_traits::to_value_ptr( pDel ), pos, key_comparator(), false );
1420                             m_Stat.onSlowErase();
1421                             return true;
1422                         }
1423                     }
1424
1425                     // Fast erasing success
1426                     gc::retire( node_traits::to_value_ptr( pDel ), dispose_node );
1427                     m_Stat.onFastErase();
1428                     return true;
1429                 }
1430                 else {
1431                     if ( p.bits() ) {
1432                         // Another thread is deleting pDel right now
1433                         return false;
1434                     }
1435                 }
1436                 m_Stat.onEraseRetry();
1437             }
1438         }
1439
1440         enum finsd_fastpath_result {
1441             find_fastpath_found,
1442             find_fastpath_not_found,
1443             find_fastpath_abort
1444         };
1445         template <typename Q, typename Compare, typename Func>
1446         finsd_fastpath_result find_fastpath( Q& val, Compare cmp, Func f )
1447         {
1448             node_type * pPred;
1449             typename gc::template GuardArray<2>  guards;
1450             marked_node_ptr pCur;
1451             marked_node_ptr pNull;
1452
1453             back_off bkoff;
1454
1455             pPred = m_Head.head();
1456             for ( int nLevel = static_cast<int>( m_nHeight.load( memory_model::memory_order_relaxed ) - 1 ); nLevel >= 0; --nLevel ) {
1457                 pCur = guards.protect( 1, pPred->next( nLevel ), gc_protect );
1458                 if ( pCur == pNull )
1459                     continue;
1460
1461                 while ( pCur != pNull ) {
1462                     if ( pCur.bits() ) {
1463                         unsigned int nAttempt = 0;
1464                         bkoff.reset();
1465                         while ( pCur.bits() && nAttempt++ < 16 ) {
1466                             bkoff();
1467                             pCur = guards.protect( 1, pPred->next( nLevel ), gc_protect );
1468                         }
1469
1470                         if ( pCur.bits() ) {
1471                             // Maybe, we are on deleted node sequence
1472                             // Abort searching, try slow-path
1473                             return find_fastpath_abort;
1474                         }
1475                     }
1476
1477                     if ( pCur.ptr() ) {
1478                         int nCmp = cmp( *node_traits::to_value_ptr( pCur.ptr() ), val );
1479                         if ( nCmp < 0 ) {
1480                             guards.copy( 0, 1 );
1481                             pPred = pCur.ptr();
1482                             pCur = guards.protect( 1, pCur->next( nLevel ), gc_protect );
1483                         }
1484                         else if ( nCmp == 0 ) {
1485                             // found
1486                             f( *node_traits::to_value_ptr( pCur.ptr() ), val );
1487                             return find_fastpath_found;
1488                         }
1489                         else // pCur > val - go down
1490                             break;
1491                     }
1492                 }
1493             }
1494
1495             return find_fastpath_not_found;
1496         }
1497
1498         template <typename Q, typename Compare, typename Func>
1499         bool find_slowpath( Q& val, Compare cmp, Func f )
1500         {
1501             position pos;
1502             if ( find_position( val, pos, cmp, true ) ) {
1503                 assert( cmp( *node_traits::to_value_ptr( pos.pCur ), val ) == 0 );
1504
1505                 f( *node_traits::to_value_ptr( pos.pCur ), val );
1506                 return true;
1507             }
1508             else
1509                 return false;
1510         }
1511
1512         template <typename Q, typename Compare, typename Func>
1513         bool find_with_( Q& val, Compare cmp, Func f )
1514         {
1515             switch ( find_fastpath( val, cmp, f ) ) {
1516             case find_fastpath_found:
1517                 m_Stat.onFindFastSuccess();
1518                 return true;
1519             case find_fastpath_not_found:
1520                 m_Stat.onFindFastFailed();
1521                 return false;
1522             default:
1523                 break;
1524             }
1525
1526             if ( find_slowpath( val, cmp, f ) ) {
1527                 m_Stat.onFindSlowSuccess();
1528                 return true;
1529             }
1530
1531             m_Stat.onFindSlowFailed();
1532             return false;
1533         }
1534
1535         template <typename Q, typename Compare>
1536         guarded_ptr get_with_( Q const& val, Compare cmp )
1537         {
1538             guarded_ptr gp;
1539             if ( find_with_( val, cmp, [&gp]( value_type& found, Q const& ) { gp.reset( &found ); } ) )
1540                 return gp;
1541             return guarded_ptr();
1542         }
1543
1544         template <typename Q, typename Compare, typename Func>
1545         bool erase_( Q const& val, Compare cmp, Func f )
1546         {
1547             position pos;
1548
1549             if ( !find_position( val, pos, cmp, false ) ) {
1550                 m_Stat.onEraseFailed();
1551                 return false;
1552             }
1553
1554             node_type * pDel = pos.pCur;
1555             typename gc::Guard gDel;
1556             gDel.assign( node_traits::to_value_ptr( pDel ) );
1557             assert( cmp( *node_traits::to_value_ptr( pDel ), val ) == 0 );
1558
1559             unsigned int nHeight = pDel->height();
1560             if ( try_remove_at( pDel, pos, f ) ) {
1561                 --m_ItemCounter;
1562                 m_Stat.onRemoveNode( nHeight );
1563                 m_Stat.onEraseSuccess();
1564                 return true;
1565             }
1566
1567             m_Stat.onEraseFailed();
1568             return false;
1569         }
1570
1571         template <typename Q, typename Compare>
1572         guarded_ptr extract_( Q const& val, Compare cmp )
1573         {
1574             position pos;
1575
1576             guarded_ptr gp;
1577             for ( ;;) {
1578                 if ( !find_position( val, pos, cmp, false ) ) {
1579                     m_Stat.onExtractFailed();
1580                     return guarded_ptr();
1581                 }
1582
1583                 node_type * pDel = pos.pCur;
1584                 gp.reset( node_traits::to_value_ptr( pDel ) );
1585                 assert( cmp( *node_traits::to_value_ptr( pDel ), val ) == 0 );
1586
1587                 unsigned int nHeight = pDel->height();
1588                 if ( try_remove_at( pDel, pos, []( value_type const& ) {} ) ) {
1589                     --m_ItemCounter;
1590                     m_Stat.onRemoveNode( nHeight );
1591                     m_Stat.onExtractSuccess();
1592                     return gp;
1593                 }
1594                 m_Stat.onExtractRetry();
1595             }
1596         }
1597
1598         guarded_ptr extract_min_()
1599         {
1600             position pos;
1601
1602             guarded_ptr gp;
1603             for ( ;;) {
1604                 if ( !find_min_position( pos ) ) {
1605                     // The list is empty
1606                     m_Stat.onExtractMinFailed();
1607                     return guarded_ptr();
1608                 }
1609
1610                 node_type * pDel = pos.pCur;
1611
1612                 unsigned int nHeight = pDel->height();
1613                 gp.reset( node_traits::to_value_ptr( pDel ) );
1614
1615                 if ( try_remove_at( pDel, pos, []( value_type const& ) {} ) ) {
1616                     --m_ItemCounter;
1617                     m_Stat.onRemoveNode( nHeight );
1618                     m_Stat.onExtractMinSuccess();
1619                     return gp;
1620                 }
1621
1622                 m_Stat.onExtractMinRetry();
1623             }
1624         }
1625
1626         guarded_ptr extract_max_()
1627         {
1628             position pos;
1629
1630             guarded_ptr gp;
1631             for ( ;;) {
1632                 if ( !find_max_position( pos ) ) {
1633                     // The list is empty
1634                     m_Stat.onExtractMaxFailed();
1635                     return guarded_ptr();
1636                 }
1637
1638                 node_type * pDel = pos.pCur;
1639
1640                 unsigned int nHeight = pDel->height();
1641                 gp.reset( node_traits::to_value_ptr( pDel ) );
1642
1643                 if ( try_remove_at( pDel, pos, []( value_type const& ) {} ) ) {
1644                     --m_ItemCounter;
1645                     m_Stat.onRemoveNode( nHeight );
1646                     m_Stat.onExtractMaxSuccess();
1647                     return gp;
1648                 }
1649
1650                 m_Stat.onExtractMaxRetry();
1651             }
1652         }
1653
1654         void increase_height( unsigned int nHeight )
1655         {
1656             unsigned int nCur = m_nHeight.load( memory_model::memory_order_relaxed );
1657             if ( nCur < nHeight )
1658                 m_nHeight.compare_exchange_strong( nCur, nHeight, memory_model::memory_order_release, atomics::memory_order_relaxed );
1659         }
1660         //@endcond
1661
1662     private:
1663         //@cond
1664         skip_list::details::head_node< node_type > m_Head;   ///< head tower (max height)
1665
1666         item_counter                m_ItemCounter;    ///< item counter
1667         random_level_generator      m_RandomLevelGen; ///< random level generator instance
1668         atomics::atomic<unsigned int> m_nHeight;      ///< estimated high level
1669         mutable stat                m_Stat;           ///< internal statistics
1670         //@endcond
1671     };
1672
1673 }} // namespace cds::intrusive
1674
1675
1676 #endif // #ifndef CDSLIB_INTRUSIVE_IMPL_SKIP_LIST_H