Moce skip_list_base.h from cds/intrusive tocds/intrusive/details
authorkhizmax <libcds.dev@gmail.com>
Sat, 27 Sep 2014 15:45:04 +0000 (19:45 +0400)
committerkhizmax <libcds.dev@gmail.com>
Sat, 27 Sep 2014 15:45:04 +0000 (19:45 +0400)
cds/container/skip_list_base.h
cds/intrusive/details/skip_list_base.h [new file with mode: 0644]
cds/intrusive/skip_list_base.h [deleted file]
cds/intrusive/skip_list_impl.h
cds/intrusive/skip_list_nogc.h
cds/intrusive/skip_list_rcu.h
projects/Win/vc12/cds.vcxproj
projects/Win/vc12/cds.vcxproj.filters
tests/unit/print_skip_list_stat.h

index bf33f0cc32f3e0fa4b3534f821870c52d4fab266..3cc591b57f23c3f9349efe7cbbc9d00b295b18eb 100644 (file)
@@ -3,7 +3,7 @@
 #ifndef __CDS_CONTAINER_SKIP_LIST_BASE_H
 #define __CDS_CONTAINER_SKIP_LIST_BASE_H
 
-#include <cds/intrusive/skip_list_base.h>
+#include <cds/intrusive/details/skip_list_base.h>
 #include <cds/container/base.h>
 
 namespace cds { namespace container {
diff --git a/cds/intrusive/details/skip_list_base.h b/cds/intrusive/details/skip_list_base.h
new file mode 100644 (file)
index 0000000..257e2bb
--- /dev/null
@@ -0,0 +1,654 @@
+//$$CDS-header$$
+
+#ifndef __CDS_INTRUSIVE_DETAILS_SKIP_LIST_BASE_H
+#define __CDS_INTRUSIVE_DETAILS_SKIP_LIST_BASE_H
+
+#include <cds/intrusive/details/base.h>
+#include <cds/details/marked_ptr.h>
+#include <cds/algo/bitop.h>
+#include <cds/os/timer.h>
+#include <cds/urcu/options.h>
+
+
+namespace cds { namespace intrusive {
+    /// SkipListSet related definitions
+    /** @ingroup cds_intrusive_helper
+    */
+    namespace skip_list {
+
+        /// The maximum possible height of any skip-list
+        static unsigned int const c_nHeightLimit = 32;
+
+        /// Skip list node
+        /**
+            Template parameters:
+            - GC - garbage collector
+            - Tag - a tag used to distinguish between different implementation. An incomplete type may be used as a tag.
+        */
+        template <class GC, typename Tag = opt::none>
+        class node {
+        public:
+            typedef GC      gc          ;   ///< Garbage collector
+            typedef Tag     tag         ;   ///< tag
+
+            typedef cds::details::marked_ptr<node, 1>                       marked_ptr          ;   ///< marked pointer
+            typedef typename gc::template atomic_marked_ptr< marked_ptr>    atomic_marked_ptr   ;   ///< atomic marked pointer specific for GC
+            //@cond
+            typedef atomic_marked_ptr tower_item_type;
+            //@endcond
+
+        protected:
+            atomic_marked_ptr       m_pNext     ;   ///< Next item in bottom-list (list at level 0)
+            unsigned int            m_nHeight   ;   ///< Node height (size of m_arrNext array). For node at level 0 the height is 1.
+            atomic_marked_ptr *     m_arrNext   ;   ///< Array of next items for levels 1 .. m_nHeight - 1. For node at level 0 \p m_arrNext is \p nullptr
+
+        public:
+            /// Constructs a node of height 1 (a bottom-list node)
+            node()
+                : m_pNext( nullptr )
+                , m_nHeight(1)
+                , m_arrNext( nullptr )
+            {}
+
+            /// Constructs a node of height \p nHeight
+            void make_tower( unsigned int nHeight, atomic_marked_ptr * nextTower )
+            {
+                assert( nHeight > 0 );
+                assert( (nHeight == 1 && nextTower == nullptr)  // bottom-list node
+                        || (nHeight > 1 && nextTower != nullptr)   // node at level of more than 0
+                );
+
+                m_arrNext = nextTower;
+                m_nHeight = nHeight;
+            }
+
+            //@cond
+            atomic_marked_ptr * release_tower()
+            {
+                atomic_marked_ptr * pTower = m_arrNext;
+                m_arrNext = nullptr;
+                m_nHeight = 1;
+                return pTower;
+            }
+
+            atomic_marked_ptr * get_tower() const
+            {
+                return m_arrNext;
+            }
+            //@endcond
+
+            /// Access to element of next pointer array
+            atomic_marked_ptr& next( unsigned int nLevel )
+            {
+                assert( nLevel < height() );
+                assert( nLevel == 0 || (nLevel > 0 && m_arrNext != nullptr) );
+
+                return nLevel ? m_arrNext[ nLevel - 1] : m_pNext;
+            }
+
+            /// Access to element of next pointer array (const version)
+            atomic_marked_ptr const& next( unsigned int nLevel ) const
+            {
+                assert( nLevel < height() );
+                assert( nLevel == 0 || nLevel > 0 && m_arrNext != nullptr );
+
+                return nLevel ? m_arrNext[ nLevel - 1] : m_pNext;
+            }
+
+            /// Access to element of next pointer array (same as \ref next function)
+            atomic_marked_ptr& operator[]( unsigned int nLevel )
+            {
+                return next( nLevel );
+            }
+
+            /// Access to element of next pointer array (same as \ref next function)
+            atomic_marked_ptr const& operator[]( unsigned int nLevel ) const
+            {
+                return next( nLevel );
+            }
+
+            /// Height of the node
+            unsigned int height() const
+            {
+                return m_nHeight;
+            }
+
+            /// Clears internal links
+            void clear()
+            {
+                assert( m_arrNext == nullptr );
+                m_pNext.store( marked_ptr(), atomics::memory_order_release );
+            }
+
+            //@cond
+            bool is_cleared() const
+            {
+                return m_pNext == atomic_marked_ptr()
+                    && m_arrNext == nullptr
+                    && m_nHeight <= 1
+;
+            }
+            //@endcond
+        };
+
+        //@cond
+        struct undefined_gc;
+        struct default_hook {
+            typedef undefined_gc    gc;
+            typedef opt::none       tag;
+        };
+        //@endcond
+
+        //@cond
+        template < typename HookType, typename... Options>
+        struct hook
+        {
+            typedef typename opt::make_options< default_hook, Options...>::type  options;
+            typedef typename options::gc    gc;
+            typedef typename options::tag   tag;
+            typedef node<gc, tag>           node_type;
+            typedef HookType                hook_type;
+        };
+        //@endcond
+
+        /// Base hook
+        /**
+            \p Options are:
+            - opt::gc - garbage collector used.
+            - opt::tag - a tag
+        */
+        template < typename... Options >
+        struct base_hook: public hook< opt::base_hook_tag, Options... >
+        {};
+
+        /// Member hook
+        /**
+            \p MemberOffset defines offset in bytes of \ref node member into your structure.
+            Use \p offsetof macro to define \p MemberOffset
+
+            \p Options are:
+            - opt::gc - garbage collector used.
+            - opt::tag - a tag
+        */
+        template < size_t MemberOffset, typename... Options >
+        struct member_hook: public hook< opt::member_hook_tag, Options... >
+        {
+            //@cond
+            static const size_t c_nMemberOffset = MemberOffset;
+            //@endcond
+        };
+
+        /// Traits hook
+        /**
+            \p NodeTraits defines type traits for node.
+            See \ref node_traits for \p NodeTraits interface description
+
+            \p Options are:
+            - opt::gc - garbage collector used.
+            - opt::tag - a tag
+        */
+        template <typename NodeTraits, typename... Options >
+        struct traits_hook: public hook< opt::traits_hook_tag, Options... >
+        {
+            //@cond
+            typedef NodeTraits node_traits;
+            //@endcond
+        };
+
+        /// Option specifying random level generator
+        /**
+            The random level generator is an important part of skip-list algorithm.
+            The node height in the skip-list have a probabilistic distribution
+            where half of the nodes that have level \p i pointers also have level <tt>i+1</tt> pointers
+            (i = 0..30).
+            The random level generator should provide such distribution.
+
+            The \p Type functor interface is:
+            \code
+            struct random_generator {
+                static unsigned int const c_nUpperBound = 32;
+                random_generator();
+                unsigned int operator()();
+            };
+            \endcode
+
+            where
+            - \p c_nUpperBound - constant that specifies the upper bound of random number generated.
+                The generator produces a number from range <tt>[0 .. c_nUpperBound)</tt> (upper bound excluded).
+                \p c_nUpperBound must be no more than 32.
+            - <tt>random_generator()</tt> - the constructor of generator object initialises the generator instance (its internal state).
+            - <tt>unsigned int operator()()</tt> - the main generating function. Returns random level from range 0..31.
+
+            Stateful generators are supported.
+
+            Available \p Type implementations:
+            - \ref xorshift
+            - \ref turbo_pascal
+        */
+        template <typename Type>
+        struct random_level_generator {
+            //@cond
+            template <typename Base>
+            struct pack: public Base
+            {
+                typedef Type random_level_generator;
+            };
+            //@endcond
+        };
+
+        /// Xor-shift random level generator
+        /**
+            The simplest of the generators described in George
+            Marsaglia's "Xorshift RNGs" paper.  This is not a high-quality
+            generator but is acceptable for skip-list.
+
+            The random generator should return numbers from range [0..31].
+
+            From Doug Lea's ConcurrentSkipListMap.java.
+        */
+        class xorshift {
+            //@cond
+            atomics::atomic<unsigned int>    m_nSeed;
+            //@endcond
+        public:
+            /// The upper bound of generator's return value. The generator produces random number in range <tt>[0..c_nUpperBound)</tt>
+            static unsigned int const c_nUpperBound = c_nHeightLimit;
+
+            /// Initializes the generator instance
+            xorshift()
+            {
+                m_nSeed.store( (unsigned int) cds::OS::Timer::random_seed(), atomics::memory_order_relaxed );
+            }
+
+            /// Main generator function
+            unsigned int operator()()
+            {
+                /* ConcurrentSkipListMap.java
+                private int randomLevel() {
+                    int x = randomSeed;
+                    x ^= x << 13;
+                    x ^= x >>> 17;
+                    randomSeed = x ^= x << 5;
+                    if ((x & 0x80000001) != 0) // test highest and lowest bits
+                        return 0;
+                    int level = 1;
+                    while (((x >>>= 1) & 1) != 0) ++level;
+                    return level;
+                }
+                */
+                unsigned int x = m_nSeed.load( atomics::memory_order_relaxed );
+                x ^= x << 13;
+                x ^= x >> 17;
+                x ^= x << 5;
+                m_nSeed.store( x, atomics::memory_order_relaxed );
+                unsigned int nLevel = ((x & 0x00000001) != 0) ? 0 : cds::bitop::LSB( (~(x >> 1)) & 0x7FFFFFFF );
+                assert( nLevel < c_nUpperBound );
+                return nLevel;
+            }
+        };
+
+        /// Turbo-pascal random level generator
+        /**
+            This uses a cheap pseudo-random function that was used in Turbo Pascal.
+
+            The random generator should return numbers from range [0..31].
+
+            From Doug Lea's ConcurrentSkipListMap.java.
+        */
+        class turbo_pascal
+        {
+            //@cond
+            atomics::atomic<unsigned int>    m_nSeed;
+            //@endcond
+        public:
+            /// The upper bound of generator's return value. The generator produces random number in range <tt>[0..c_nUpperBound)</tt>
+            static unsigned int const c_nUpperBound = c_nHeightLimit;
+
+            /// Initializes the generator instance
+            turbo_pascal()
+            {
+                m_nSeed.store( (unsigned int) cds::OS::Timer::random_seed(), atomics::memory_order_relaxed );
+            }
+
+            /// Main generator function
+            unsigned int operator()()
+            {
+                /*
+                private int randomLevel() {
+                    int level = 0;
+                    int r = randomSeed;
+                    randomSeed = r * 134775813 + 1;
+                    if (r < 0) {
+                        while ((r <<= 1) > 0)
+                            ++level;
+                    }
+                return level;
+                }
+                */
+                /*
+                    The low bits are apparently not very random (the original used only
+                    upper 16 bits) so we traverse from highest bit down (i.e., test
+                    sign), thus hardly ever use lower bits.
+                */
+                unsigned int x = m_nSeed.load( atomics::memory_order_relaxed ) * 134775813 + 1;
+                m_nSeed.store( x, atomics::memory_order_relaxed );
+                unsigned int nLevel = ( x & 0x80000000 ) ? (31 - cds::bitop::MSBnz( (x & 0x7FFFFFFF) | 1 )) : 0;
+                assert( nLevel < c_nUpperBound );
+                return nLevel;
+            }
+        };
+
+        /// SkipListSet internal statistics
+        template <typename EventCounter = cds::atomicity::event_counter>
+        struct stat {
+            typedef EventCounter event_counter ; ///< Event counter type
+
+            event_counter   m_nNodeHeightAdd[c_nHeightLimit] ; ///< Count of added node of each height
+            event_counter   m_nNodeHeightDel[c_nHeightLimit] ; ///< Count of deleted node of each height
+            event_counter   m_nInsertSuccess        ; ///< Count of success insertion
+            event_counter   m_nInsertFailed         ; ///< Count of failed insertion
+            event_counter   m_nInsertRetries        ; ///< Count of unsuccessful retries of insertion
+            event_counter   m_nEnsureExist          ; ///< Count of \p ensure call for existed node
+            event_counter   m_nEnsureNew            ; ///< Count of \p ensure call for new node
+            event_counter   m_nUnlinkSuccess        ; ///< Count of successful call of \p unlink
+            event_counter   m_nUnlinkFailed         ; ///< Count of failed call of \p unlink
+            event_counter   m_nEraseSuccess         ; ///< Count of successful call of \p erase
+            event_counter   m_nEraseFailed          ; ///< Count of failed call of \p erase
+            event_counter   m_nFindFastSuccess      ; ///< Count of successful call of \p find and all derivatives (via fast-path)
+            event_counter   m_nFindFastFailed       ; ///< Count of failed call of \p find and all derivatives (via fast-path)
+            event_counter   m_nFindSlowSuccess      ; ///< Count of successful call of \p find and all derivatives (via slow-path)
+            event_counter   m_nFindSlowFailed       ; ///< Count of failed call of \p find and all derivatives (via slow-path)
+            event_counter   m_nRenewInsertPosition  ; ///< Count of renewing position events while inserting
+            event_counter   m_nLogicDeleteWhileInsert   ;   ///< Count of events "The node has been logically deleted while inserting"
+            event_counter   m_nNotFoundWhileInsert  ; ///< Count of events "Inserting node is not found"
+            event_counter   m_nFastErase            ; ///< Fast erase event counter
+            event_counter   m_nFastExtract          ; ///< Fast extract event counter
+            event_counter   m_nSlowErase            ; ///< Slow erase event counter
+            event_counter   m_nSlowExtract          ; ///< Slow extract event counter
+            event_counter   m_nExtractSuccess       ; ///< Count of successful call of \p extract
+            event_counter   m_nExtractFailed        ; ///< Count of failed call of \p extract
+            event_counter   m_nExtractRetries       ; ///< Count of retries of \p extract call
+            event_counter   m_nExtractMinSuccess    ; ///< Count of successful call of \p extract_min
+            event_counter   m_nExtractMinFailed     ; ///< Count of failed call of \p extract_min
+            event_counter   m_nExtractMinRetries    ; ///< Count of retries of \p extract_min call
+            event_counter   m_nExtractMaxSuccess    ; ///< Count of successful call of \p extract_max
+            event_counter   m_nExtractMaxFailed     ; ///< Count of failed call of \p extract_max
+            event_counter   m_nExtractMaxRetries    ; ///< Count of retries of \p extract_max call
+            event_counter   m_nEraseWhileFind       ; ///< Count of erased item while searching
+            event_counter   m_nExtractWhileFind     ; ///< Count of extracted item while searching (RCU only)
+
+            //@cond
+            void onAddNode( unsigned int nHeight )
+            {
+                assert( nHeight > 0 && nHeight <= sizeof(m_nNodeHeightAdd) / sizeof(m_nNodeHeightAdd[0]));
+                ++m_nNodeHeightAdd[nHeight - 1];
+            }
+            void onRemoveNode( unsigned int nHeight )
+            {
+                assert( nHeight > 0 && nHeight <= sizeof(m_nNodeHeightDel) / sizeof(m_nNodeHeightDel[0]));
+                ++m_nNodeHeightDel[nHeight - 1];
+            }
+
+            void onInsertSuccess()          { ++m_nInsertSuccess    ; }
+            void onInsertFailed()           { ++m_nInsertFailed     ; }
+            void onInsertRetry()            { ++m_nInsertRetries    ; }
+            void onEnsureExist()            { ++m_nEnsureExist      ; }
+            void onEnsureNew()              { ++m_nEnsureNew        ; }
+            void onUnlinkSuccess()          { ++m_nUnlinkSuccess    ; }
+            void onUnlinkFailed()           { ++m_nUnlinkFailed     ; }
+            void onEraseSuccess()           { ++m_nEraseSuccess     ; }
+            void onEraseFailed()            { ++m_nEraseFailed      ; }
+            void onFindFastSuccess()        { ++m_nFindFastSuccess  ; }
+            void onFindFastFailed()         { ++m_nFindFastFailed   ; }
+            void onFindSlowSuccess()        { ++m_nFindSlowSuccess  ; }
+            void onFindSlowFailed()         { ++m_nFindSlowFailed   ; }
+            void onEraseWhileFind()         { ++m_nEraseWhileFind   ; }
+            void onExtractWhileFind()       { ++m_nExtractWhileFind ; }
+            void onRenewInsertPosition()    { ++m_nRenewInsertPosition; }
+            void onLogicDeleteWhileInsert() { ++m_nLogicDeleteWhileInsert; }
+            void onNotFoundWhileInsert()    { ++m_nNotFoundWhileInsert; }
+            void onFastErase()              { ++m_nFastErase;         }
+            void onFastExtract()            { ++m_nFastExtract;       }
+            void onSlowErase()              { ++m_nSlowErase;         }
+            void onSlowExtract()            { ++m_nSlowExtract;       }
+            void onExtractSuccess()         { ++m_nExtractSuccess;    }
+            void onExtractFailed()          { ++m_nExtractFailed;     }
+            void onExtractRetry()           { ++m_nExtractRetries;    }
+            void onExtractMinSuccess()      { ++m_nExtractMinSuccess; }
+            void onExtractMinFailed()       { ++m_nExtractMinFailed;  }
+            void onExtractMinRetry()        { ++m_nExtractMinRetries; }
+            void onExtractMaxSuccess()      { ++m_nExtractMaxSuccess; }
+            void onExtractMaxFailed()       { ++m_nExtractMaxFailed;  }
+            void onExtractMaxRetry()        { ++m_nExtractMaxRetries; }
+
+            //@endcond
+        };
+
+        /// SkipListSet empty internal statistics
+        struct empty_stat {
+            //@cond
+            void onAddNode( unsigned int nHeight ) const {}
+            void onRemoveNode( unsigned int nHeight ) const {}
+            void onInsertSuccess()          const {}
+            void onInsertFailed()           const {}
+            void onInsertRetry()            const {}
+            void onEnsureExist()            const {}
+            void onEnsureNew()              const {}
+            void onUnlinkSuccess()          const {}
+            void onUnlinkFailed()           const {}
+            void onEraseSuccess()           const {}
+            void onEraseFailed()            const {}
+            void onFindFastSuccess()        const {}
+            void onFindFastFailed()         const {}
+            void onFindSlowSuccess()        const {}
+            void onFindSlowFailed()         const {}
+            void onEraseWhileFind()         const {}
+            void onExtractWhileFind()       const {}
+            void onRenewInsertPosition()    const {}
+            void onLogicDeleteWhileInsert() const {}
+            void onNotFoundWhileInsert()    const {}
+            void onFastErase()              const {}
+            void onFastExtract()            const {}
+            void onSlowErase()              const {}
+            void onSlowExtract()            const {}
+            void onExtractSuccess()         const {}
+            void onExtractFailed()          const {}
+            void onExtractRetry()           const {}
+            void onExtractMinSuccess()      const {}
+            void onExtractMinFailed()       const {}
+            void onExtractMinRetry()        const {}
+            void onExtractMaxSuccess()      const {}
+            void onExtractMaxFailed()       const {}
+            void onExtractMaxRetry()        const {}
+
+            //@endcond
+        };
+
+        //@cond
+        // For internal use only!!!
+        template <typename Type>
+        struct internal_node_builder {
+            template <typename Base>
+            struct pack: public Base
+            {
+                typedef Type internal_node_builder;
+            };
+        };
+        //@endcond
+
+        /// Type traits for SkipListSet class
+        struct type_traits
+        {
+            /// Hook used
+            /**
+                Possible values are: skip_list::base_hook, skip_list::member_hook, skip_list::traits_hook.
+            */
+            typedef base_hook<>       hook;
+
+            /// Key comparison functor
+            /**
+                No default functor is provided. If the option is not specified, the \p less is used.
+            */
+            typedef opt::none                       compare;
+
+            /// specifies binary predicate used for key compare.
+            /**
+                Default is \p std::less<T>.
+            */
+            typedef opt::none                       less;
+
+            /// Disposer
+            /**
+                The functor used for dispose removed items. Default is opt::v::empty_disposer.
+            */
+            typedef opt::v::empty_disposer          disposer;
+
+            /// Item counter
+            /**
+                The type for item counting feature.
+                Default is no item counter (\ref atomicity::empty_item_counter)
+            */
+            typedef atomicity::empty_item_counter     item_counter;
+
+            /// C++ memory ordering model
+            /**
+                List of available memory ordering see opt::memory_model
+            */
+            typedef opt::v::relaxed_ordering        memory_model;
+
+            /// Random level generator
+            /**
+                The random level generator is an important part of skip-list algorithm.
+                The node height in the skip-list have a probabilistic distribution
+                where half of the nodes that have level \p i pointers also have level <tt>i+1</tt> pointers
+                (i = 0..30). So, the height of a node is in range [0..31].
+
+                See skip_list::random_level_generator option setter.
+            */
+            typedef turbo_pascal                    random_level_generator;
+
+            /// Allocator
+            /**
+                Although the skip-list is an intrusive container,
+                an allocator should be provided to maintain variable randomly-calculated height of the node
+                since the node can contain up to 32 next pointers.
+                The allocator specified is used to allocate an array of next pointers
+                for nodes which height is more than 1.
+            */
+            typedef CDS_DEFAULT_ALLOCATOR           allocator;
+
+            /// back-off strategy used
+            /**
+                If the option is not specified, the cds::backoff::Default is used.
+            */
+            typedef cds::backoff::Default           back_off;
+
+            /// Internal statistics
+            typedef empty_stat                      stat;
+
+            /// RCU deadlock checking policy (only for \ref cds_intrusive_SkipListSet_rcu "RCU-based SkipListSet")
+            /**
+                List of available options see opt::rcu_check_deadlock
+            */
+            typedef opt::v::rcu_throw_deadlock      rcu_check_deadlock;
+
+            //@cond
+            // For internal use only!!!
+            typedef opt::none                       internal_node_builder;
+            //@endcond
+        };
+
+        /// Metafunction converting option list to SkipListSet traits
+        /**
+            This is a wrapper for <tt> cds::opt::make_options< type_traits, Options...> </tt>
+            \p Options list see \ref SkipListSet.
+        */
+        template <typename... Options>
+        struct make_traits {
+#   ifdef CDS_DOXYGEN_INVOKED
+            typedef implementation_defined type ;   ///< Metafunction result
+#   else
+            typedef typename cds::opt::make_options<
+                typename cds::opt::find_type_traits< type_traits, Options... >::type
+                ,Options...
+            >::type   type;
+#   endif
+        };
+
+        //@cond
+        namespace details {
+            template <typename Node>
+            class head_node: public Node
+            {
+                typedef Node node_type;
+
+                typename node_type::atomic_marked_ptr   m_Tower[skip_list::c_nHeightLimit];
+
+            public:
+                head_node( unsigned int nHeight )
+                {
+                    for ( size_t i = 0; i < sizeof(m_Tower) / sizeof(m_Tower[0]); ++i )
+                        m_Tower[i].store( typename node_type::marked_ptr(), atomics::memory_order_relaxed );
+
+                    node_type::make_tower( nHeight, m_Tower );
+                }
+
+                node_type * head() const
+                {
+                    return const_cast<node_type *>( static_cast<node_type const *>(this));
+                }
+            };
+
+            template <typename NodeType, typename AtomicNodePtr, typename Alloc>
+            struct intrusive_node_builder
+            {
+                typedef NodeType        node_type;
+                typedef AtomicNodePtr   atomic_node_ptr;
+                typedef Alloc           allocator_type;
+
+                typedef cds::details::Allocator< atomic_node_ptr, allocator_type >  tower_allocator;
+
+                template <typename RandomGen>
+                static node_type * make_tower( node_type * pNode, RandomGen& gen )
+                {
+                    return make_tower( pNode, gen() + 1 );
+                }
+
+                static node_type * make_tower( node_type * pNode, unsigned int nHeight )
+                {
+                    if ( nHeight > 1 )
+                        pNode->make_tower( nHeight, tower_allocator().NewArray( nHeight - 1, nullptr ) );
+                    return pNode;
+                }
+
+                static void dispose_tower( node_type * pNode )
+                {
+                    unsigned int nHeight = pNode->height();
+                    if ( nHeight > 1 )
+                        tower_allocator().Delete( pNode->release_tower(), nHeight );
+                }
+
+                struct node_disposer {
+                    void operator()( node_type * pNode )
+                    {
+                        dispose_tower( pNode );
+                    }
+                };
+            };
+
+            // Forward declaration
+            template <class GC, typename NodeTraits, typename BackOff, bool IsConst>
+            class iterator;
+
+        } // namespace details
+        //@endcond
+
+    }   // namespace skip_list
+
+    // Forward declaration
+    template <class GC, typename T, typename Traits = skip_list::type_traits >
+    class SkipListSet;
+
+}}   // namespace cds::intrusive
+
+#endif // #ifndef __CDS_INTRUSIVE_DETAILS_SKIP_LIST_BASE_H
diff --git a/cds/intrusive/skip_list_base.h b/cds/intrusive/skip_list_base.h
deleted file mode 100644 (file)
index 5419dc4..0000000
+++ /dev/null
@@ -1,654 +0,0 @@
-//$$CDS-header$$
-
-#ifndef __CDS_INTRUSIVE_SKIP_LIST_BASE_H
-#define __CDS_INTRUSIVE_SKIP_LIST_BASE_H
-
-#include <cds/intrusive/details/base.h>
-#include <cds/details/marked_ptr.h>
-#include <cds/algo/bitop.h>
-#include <cds/os/timer.h>
-#include <cds/urcu/options.h>
-
-
-namespace cds { namespace intrusive {
-    /// SkipListSet related definitions
-    /** @ingroup cds_intrusive_helper
-    */
-    namespace skip_list {
-
-        /// The maximum possible height of any skip-list
-        static unsigned int const c_nHeightLimit = 32;
-
-        /// Skip list node
-        /**
-            Template parameters:
-            - GC - garbage collector
-            - Tag - a tag used to distinguish between different implementation. An incomplete type may be used as a tag.
-        */
-        template <class GC, typename Tag = opt::none>
-        class node {
-        public:
-            typedef GC      gc          ;   ///< Garbage collector
-            typedef Tag     tag         ;   ///< tag
-
-            typedef cds::details::marked_ptr<node, 1>                       marked_ptr          ;   ///< marked pointer
-            typedef typename gc::template atomic_marked_ptr< marked_ptr>    atomic_marked_ptr   ;   ///< atomic marked pointer specific for GC
-            //@cond
-            typedef atomic_marked_ptr tower_item_type;
-            //@endcond
-
-        protected:
-            atomic_marked_ptr       m_pNext     ;   ///< Next item in bottom-list (list at level 0)
-            unsigned int            m_nHeight   ;   ///< Node height (size of m_arrNext array). For node at level 0 the height is 1.
-            atomic_marked_ptr *     m_arrNext   ;   ///< Array of next items for levels 1 .. m_nHeight - 1. For node at level 0 \p m_arrNext is \p nullptr
-
-        public:
-            /// Constructs a node of height 1 (a bottom-list node)
-            node()
-                : m_pNext( nullptr )
-                , m_nHeight(1)
-                , m_arrNext( nullptr )
-            {}
-
-            /// Constructs a node of height \p nHeight
-            void make_tower( unsigned int nHeight, atomic_marked_ptr * nextTower )
-            {
-                assert( nHeight > 0 );
-                assert( (nHeight == 1 && nextTower == nullptr)  // bottom-list node
-                        || (nHeight > 1 && nextTower != nullptr)   // node at level of more than 0
-                );
-
-                m_arrNext = nextTower;
-                m_nHeight = nHeight;
-            }
-
-            //@cond
-            atomic_marked_ptr * release_tower()
-            {
-                atomic_marked_ptr * pTower = m_arrNext;
-                m_arrNext = nullptr;
-                m_nHeight = 1;
-                return pTower;
-            }
-
-            atomic_marked_ptr * get_tower() const
-            {
-                return m_arrNext;
-            }
-            //@endcond
-
-            /// Access to element of next pointer array
-            atomic_marked_ptr& next( unsigned int nLevel )
-            {
-                assert( nLevel < height() );
-                assert( nLevel == 0 || (nLevel > 0 && m_arrNext != nullptr) );
-
-                return nLevel ? m_arrNext[ nLevel - 1] : m_pNext;
-            }
-
-            /// Access to element of next pointer array (const version)
-            atomic_marked_ptr const& next( unsigned int nLevel ) const
-            {
-                assert( nLevel < height() );
-                assert( nLevel == 0 || nLevel > 0 && m_arrNext != nullptr );
-
-                return nLevel ? m_arrNext[ nLevel - 1] : m_pNext;
-            }
-
-            /// Access to element of next pointer array (same as \ref next function)
-            atomic_marked_ptr& operator[]( unsigned int nLevel )
-            {
-                return next( nLevel );
-            }
-
-            /// Access to element of next pointer array (same as \ref next function)
-            atomic_marked_ptr const& operator[]( unsigned int nLevel ) const
-            {
-                return next( nLevel );
-            }
-
-            /// Height of the node
-            unsigned int height() const
-            {
-                return m_nHeight;
-            }
-
-            /// Clears internal links
-            void clear()
-            {
-                assert( m_arrNext == nullptr );
-                m_pNext.store( marked_ptr(), atomics::memory_order_release );
-            }
-
-            //@cond
-            bool is_cleared() const
-            {
-                return m_pNext == atomic_marked_ptr()
-                    && m_arrNext == nullptr
-                    && m_nHeight <= 1
-;
-            }
-            //@endcond
-        };
-
-        //@cond
-        struct undefined_gc;
-        struct default_hook {
-            typedef undefined_gc    gc;
-            typedef opt::none       tag;
-        };
-        //@endcond
-
-        //@cond
-        template < typename HookType, typename... Options>
-        struct hook
-        {
-            typedef typename opt::make_options< default_hook, Options...>::type  options;
-            typedef typename options::gc    gc;
-            typedef typename options::tag   tag;
-            typedef node<gc, tag>           node_type;
-            typedef HookType                hook_type;
-        };
-        //@endcond
-
-        /// Base hook
-        /**
-            \p Options are:
-            - opt::gc - garbage collector used.
-            - opt::tag - a tag
-        */
-        template < typename... Options >
-        struct base_hook: public hook< opt::base_hook_tag, Options... >
-        {};
-
-        /// Member hook
-        /**
-            \p MemberOffset defines offset in bytes of \ref node member into your structure.
-            Use \p offsetof macro to define \p MemberOffset
-
-            \p Options are:
-            - opt::gc - garbage collector used.
-            - opt::tag - a tag
-        */
-        template < size_t MemberOffset, typename... Options >
-        struct member_hook: public hook< opt::member_hook_tag, Options... >
-        {
-            //@cond
-            static const size_t c_nMemberOffset = MemberOffset;
-            //@endcond
-        };
-
-        /// Traits hook
-        /**
-            \p NodeTraits defines type traits for node.
-            See \ref node_traits for \p NodeTraits interface description
-
-            \p Options are:
-            - opt::gc - garbage collector used.
-            - opt::tag - a tag
-        */
-        template <typename NodeTraits, typename... Options >
-        struct traits_hook: public hook< opt::traits_hook_tag, Options... >
-        {
-            //@cond
-            typedef NodeTraits node_traits;
-            //@endcond
-        };
-
-        /// Option specifying random level generator
-        /**
-            The random level generator is an important part of skip-list algorithm.
-            The node height in the skip-list have a probabilistic distribution
-            where half of the nodes that have level \p i pointers also have level <tt>i+1</tt> pointers
-            (i = 0..30).
-            The random level generator should provide such distribution.
-
-            The \p Type functor interface is:
-            \code
-            struct random_generator {
-                static unsigned int const c_nUpperBound = 32;
-                random_generator();
-                unsigned int operator()();
-            };
-            \endcode
-
-            where
-            - \p c_nUpperBound - constant that specifies the upper bound of random number generated.
-                The generator produces a number from range <tt>[0 .. c_nUpperBound)</tt> (upper bound excluded).
-                \p c_nUpperBound must be no more than 32.
-            - <tt>random_generator()</tt> - the constructor of generator object initialises the generator instance (its internal state).
-            - <tt>unsigned int operator()()</tt> - the main generating function. Returns random level from range 0..31.
-
-            Stateful generators are supported.
-
-            Available \p Type implementations:
-            - \ref xorshift
-            - \ref turbo_pascal
-        */
-        template <typename Type>
-        struct random_level_generator {
-            //@cond
-            template <typename Base>
-            struct pack: public Base
-            {
-                typedef Type random_level_generator;
-            };
-            //@endcond
-        };
-
-        /// Xor-shift random level generator
-        /**
-            The simplest of the generators described in George
-            Marsaglia's "Xorshift RNGs" paper.  This is not a high-quality
-            generator but is acceptable for skip-list.
-
-            The random generator should return numbers from range [0..31].
-
-            From Doug Lea's ConcurrentSkipListMap.java.
-        */
-        class xorshift {
-            //@cond
-            atomics::atomic<unsigned int>    m_nSeed;
-            //@endcond
-        public:
-            /// The upper bound of generator's return value. The generator produces random number in range <tt>[0..c_nUpperBound)</tt>
-            static unsigned int const c_nUpperBound = c_nHeightLimit;
-
-            /// Initializes the generator instance
-            xorshift()
-            {
-                m_nSeed.store( (unsigned int) cds::OS::Timer::random_seed(), atomics::memory_order_relaxed );
-            }
-
-            /// Main generator function
-            unsigned int operator()()
-            {
-                /* ConcurrentSkipListMap.java
-                private int randomLevel() {
-                    int x = randomSeed;
-                    x ^= x << 13;
-                    x ^= x >>> 17;
-                    randomSeed = x ^= x << 5;
-                    if ((x & 0x80000001) != 0) // test highest and lowest bits
-                        return 0;
-                    int level = 1;
-                    while (((x >>>= 1) & 1) != 0) ++level;
-                    return level;
-                }
-                */
-                unsigned int x = m_nSeed.load( atomics::memory_order_relaxed );
-                x ^= x << 13;
-                x ^= x >> 17;
-                x ^= x << 5;
-                m_nSeed.store( x, atomics::memory_order_relaxed );
-                unsigned int nLevel = ((x & 0x00000001) != 0) ? 0 : cds::bitop::LSB( (~(x >> 1)) & 0x7FFFFFFF );
-                assert( nLevel < c_nUpperBound );
-                return nLevel;
-            }
-        };
-
-        /// Turbo-pascal random level generator
-        /**
-            This uses a cheap pseudo-random function that was used in Turbo Pascal.
-
-            The random generator should return numbers from range [0..31].
-
-            From Doug Lea's ConcurrentSkipListMap.java.
-        */
-        class turbo_pascal
-        {
-            //@cond
-            atomics::atomic<unsigned int>    m_nSeed;
-            //@endcond
-        public:
-            /// The upper bound of generator's return value. The generator produces random number in range <tt>[0..c_nUpperBound)</tt>
-            static unsigned int const c_nUpperBound = c_nHeightLimit;
-
-            /// Initializes the generator instance
-            turbo_pascal()
-            {
-                m_nSeed.store( (unsigned int) cds::OS::Timer::random_seed(), atomics::memory_order_relaxed );
-            }
-
-            /// Main generator function
-            unsigned int operator()()
-            {
-                /*
-                private int randomLevel() {
-                    int level = 0;
-                    int r = randomSeed;
-                    randomSeed = r * 134775813 + 1;
-                    if (r < 0) {
-                        while ((r <<= 1) > 0)
-                            ++level;
-                    }
-                return level;
-                }
-                */
-                /*
-                    The low bits are apparently not very random (the original used only
-                    upper 16 bits) so we traverse from highest bit down (i.e., test
-                    sign), thus hardly ever use lower bits.
-                */
-                unsigned int x = m_nSeed.load( atomics::memory_order_relaxed ) * 134775813 + 1;
-                m_nSeed.store( x, atomics::memory_order_relaxed );
-                unsigned int nLevel = ( x & 0x80000000 ) ? (31 - cds::bitop::MSBnz( (x & 0x7FFFFFFF) | 1 )) : 0;
-                assert( nLevel < c_nUpperBound );
-                return nLevel;
-            }
-        };
-
-        /// SkipListSet internal statistics
-        template <typename EventCounter = cds::atomicity::event_counter>
-        struct stat {
-            typedef EventCounter event_counter ; ///< Event counter type
-
-            event_counter   m_nNodeHeightAdd[c_nHeightLimit] ; ///< Count of added node of each height
-            event_counter   m_nNodeHeightDel[c_nHeightLimit] ; ///< Count of deleted node of each height
-            event_counter   m_nInsertSuccess        ; ///< Count of success insertion
-            event_counter   m_nInsertFailed         ; ///< Count of failed insertion
-            event_counter   m_nInsertRetries        ; ///< Count of unsuccessful retries of insertion
-            event_counter   m_nEnsureExist          ; ///< Count of \p ensure call for existed node
-            event_counter   m_nEnsureNew            ; ///< Count of \p ensure call for new node
-            event_counter   m_nUnlinkSuccess        ; ///< Count of successful call of \p unlink
-            event_counter   m_nUnlinkFailed         ; ///< Count of failed call of \p unlink
-            event_counter   m_nEraseSuccess         ; ///< Count of successful call of \p erase
-            event_counter   m_nEraseFailed          ; ///< Count of failed call of \p erase
-            event_counter   m_nFindFastSuccess      ; ///< Count of successful call of \p find and all derivatives (via fast-path)
-            event_counter   m_nFindFastFailed       ; ///< Count of failed call of \p find and all derivatives (via fast-path)
-            event_counter   m_nFindSlowSuccess      ; ///< Count of successful call of \p find and all derivatives (via slow-path)
-            event_counter   m_nFindSlowFailed       ; ///< Count of failed call of \p find and all derivatives (via slow-path)
-            event_counter   m_nRenewInsertPosition  ; ///< Count of renewing position events while inserting
-            event_counter   m_nLogicDeleteWhileInsert   ;   ///< Count of events "The node has been logically deleted while inserting"
-            event_counter   m_nNotFoundWhileInsert  ; ///< Count of events "Inserting node is not found"
-            event_counter   m_nFastErase            ; ///< Fast erase event counter
-            event_counter   m_nFastExtract          ; ///< Fast extract event counter
-            event_counter   m_nSlowErase            ; ///< Slow erase event counter
-            event_counter   m_nSlowExtract          ; ///< Slow extract event counter
-            event_counter   m_nExtractSuccess       ; ///< Count of successful call of \p extract
-            event_counter   m_nExtractFailed        ; ///< Count of failed call of \p extract
-            event_counter   m_nExtractRetries       ; ///< Count of retries of \p extract call
-            event_counter   m_nExtractMinSuccess    ; ///< Count of successful call of \p extract_min
-            event_counter   m_nExtractMinFailed     ; ///< Count of failed call of \p extract_min
-            event_counter   m_nExtractMinRetries    ; ///< Count of retries of \p extract_min call
-            event_counter   m_nExtractMaxSuccess    ; ///< Count of successful call of \p extract_max
-            event_counter   m_nExtractMaxFailed     ; ///< Count of failed call of \p extract_max
-            event_counter   m_nExtractMaxRetries    ; ///< Count of retries of \p extract_max call
-            event_counter   m_nEraseWhileFind       ; ///< Count of erased item while searching
-            event_counter   m_nExtractWhileFind     ; ///< Count of extracted item while searching (RCU only)
-
-            //@cond
-            void onAddNode( unsigned int nHeight )
-            {
-                assert( nHeight > 0 && nHeight <= sizeof(m_nNodeHeightAdd) / sizeof(m_nNodeHeightAdd[0]));
-                ++m_nNodeHeightAdd[nHeight - 1];
-            }
-            void onRemoveNode( unsigned int nHeight )
-            {
-                assert( nHeight > 0 && nHeight <= sizeof(m_nNodeHeightDel) / sizeof(m_nNodeHeightDel[0]));
-                ++m_nNodeHeightDel[nHeight - 1];
-            }
-
-            void onInsertSuccess()          { ++m_nInsertSuccess    ; }
-            void onInsertFailed()           { ++m_nInsertFailed     ; }
-            void onInsertRetry()            { ++m_nInsertRetries    ; }
-            void onEnsureExist()            { ++m_nEnsureExist      ; }
-            void onEnsureNew()              { ++m_nEnsureNew        ; }
-            void onUnlinkSuccess()          { ++m_nUnlinkSuccess    ; }
-            void onUnlinkFailed()           { ++m_nUnlinkFailed     ; }
-            void onEraseSuccess()           { ++m_nEraseSuccess     ; }
-            void onEraseFailed()            { ++m_nEraseFailed      ; }
-            void onFindFastSuccess()        { ++m_nFindFastSuccess  ; }
-            void onFindFastFailed()         { ++m_nFindFastFailed   ; }
-            void onFindSlowSuccess()        { ++m_nFindSlowSuccess  ; }
-            void onFindSlowFailed()         { ++m_nFindSlowFailed   ; }
-            void onEraseWhileFind()         { ++m_nEraseWhileFind   ; }
-            void onExtractWhileFind()       { ++m_nExtractWhileFind ; }
-            void onRenewInsertPosition()    { ++m_nRenewInsertPosition; }
-            void onLogicDeleteWhileInsert() { ++m_nLogicDeleteWhileInsert; }
-            void onNotFoundWhileInsert()    { ++m_nNotFoundWhileInsert; }
-            void onFastErase()              { ++m_nFastErase;         }
-            void onFastExtract()            { ++m_nFastExtract;       }
-            void onSlowErase()              { ++m_nSlowErase;         }
-            void onSlowExtract()            { ++m_nSlowExtract;       }
-            void onExtractSuccess()         { ++m_nExtractSuccess;    }
-            void onExtractFailed()          { ++m_nExtractFailed;     }
-            void onExtractRetry()           { ++m_nExtractRetries;    }
-            void onExtractMinSuccess()      { ++m_nExtractMinSuccess; }
-            void onExtractMinFailed()       { ++m_nExtractMinFailed;  }
-            void onExtractMinRetry()        { ++m_nExtractMinRetries; }
-            void onExtractMaxSuccess()      { ++m_nExtractMaxSuccess; }
-            void onExtractMaxFailed()       { ++m_nExtractMaxFailed;  }
-            void onExtractMaxRetry()        { ++m_nExtractMaxRetries; }
-
-            //@endcond
-        };
-
-        /// SkipListSet empty internal statistics
-        struct empty_stat {
-            //@cond
-            void onAddNode( unsigned int nHeight ) const {}
-            void onRemoveNode( unsigned int nHeight ) const {}
-            void onInsertSuccess()          const {}
-            void onInsertFailed()           const {}
-            void onInsertRetry()            const {}
-            void onEnsureExist()            const {}
-            void onEnsureNew()              const {}
-            void onUnlinkSuccess()          const {}
-            void onUnlinkFailed()           const {}
-            void onEraseSuccess()           const {}
-            void onEraseFailed()            const {}
-            void onFindFastSuccess()        const {}
-            void onFindFastFailed()         const {}
-            void onFindSlowSuccess()        const {}
-            void onFindSlowFailed()         const {}
-            void onEraseWhileFind()         const {}
-            void onExtractWhileFind()       const {}
-            void onRenewInsertPosition()    const {}
-            void onLogicDeleteWhileInsert() const {}
-            void onNotFoundWhileInsert()    const {}
-            void onFastErase()              const {}
-            void onFastExtract()            const {}
-            void onSlowErase()              const {}
-            void onSlowExtract()            const {}
-            void onExtractSuccess()         const {}
-            void onExtractFailed()          const {}
-            void onExtractRetry()           const {}
-            void onExtractMinSuccess()      const {}
-            void onExtractMinFailed()       const {}
-            void onExtractMinRetry()        const {}
-            void onExtractMaxSuccess()      const {}
-            void onExtractMaxFailed()       const {}
-            void onExtractMaxRetry()        const {}
-
-            //@endcond
-        };
-
-        //@cond
-        // For internal use only!!!
-        template <typename Type>
-        struct internal_node_builder {
-            template <typename Base>
-            struct pack: public Base
-            {
-                typedef Type internal_node_builder;
-            };
-        };
-        //@endcond
-
-        /// Type traits for SkipListSet class
-        struct type_traits
-        {
-            /// Hook used
-            /**
-                Possible values are: skip_list::base_hook, skip_list::member_hook, skip_list::traits_hook.
-            */
-            typedef base_hook<>       hook;
-
-            /// Key comparison functor
-            /**
-                No default functor is provided. If the option is not specified, the \p less is used.
-            */
-            typedef opt::none                       compare;
-
-            /// specifies binary predicate used for key compare.
-            /**
-                Default is \p std::less<T>.
-            */
-            typedef opt::none                       less;
-
-            /// Disposer
-            /**
-                The functor used for dispose removed items. Default is opt::v::empty_disposer.
-            */
-            typedef opt::v::empty_disposer          disposer;
-
-            /// Item counter
-            /**
-                The type for item counting feature.
-                Default is no item counter (\ref atomicity::empty_item_counter)
-            */
-            typedef atomicity::empty_item_counter     item_counter;
-
-            /// C++ memory ordering model
-            /**
-                List of available memory ordering see opt::memory_model
-            */
-            typedef opt::v::relaxed_ordering        memory_model;
-
-            /// Random level generator
-            /**
-                The random level generator is an important part of skip-list algorithm.
-                The node height in the skip-list have a probabilistic distribution
-                where half of the nodes that have level \p i pointers also have level <tt>i+1</tt> pointers
-                (i = 0..30). So, the height of a node is in range [0..31].
-
-                See skip_list::random_level_generator option setter.
-            */
-            typedef turbo_pascal                    random_level_generator;
-
-            /// Allocator
-            /**
-                Although the skip-list is an intrusive container,
-                an allocator should be provided to maintain variable randomly-calculated height of the node
-                since the node can contain up to 32 next pointers.
-                The allocator specified is used to allocate an array of next pointers
-                for nodes which height is more than 1.
-            */
-            typedef CDS_DEFAULT_ALLOCATOR           allocator;
-
-            /// back-off strategy used
-            /**
-                If the option is not specified, the cds::backoff::Default is used.
-            */
-            typedef cds::backoff::Default           back_off;
-
-            /// Internal statistics
-            typedef empty_stat                      stat;
-
-            /// RCU deadlock checking policy (only for \ref cds_intrusive_SkipListSet_rcu "RCU-based SkipListSet")
-            /**
-                List of available options see opt::rcu_check_deadlock
-            */
-            typedef opt::v::rcu_throw_deadlock      rcu_check_deadlock;
-
-            //@cond
-            // For internal use only!!!
-            typedef opt::none                       internal_node_builder;
-            //@endcond
-        };
-
-        /// Metafunction converting option list to SkipListSet traits
-        /**
-            This is a wrapper for <tt> cds::opt::make_options< type_traits, Options...> </tt>
-            \p Options list see \ref SkipListSet.
-        */
-        template <typename... Options>
-        struct make_traits {
-#   ifdef CDS_DOXYGEN_INVOKED
-            typedef implementation_defined type ;   ///< Metafunction result
-#   else
-            typedef typename cds::opt::make_options<
-                typename cds::opt::find_type_traits< type_traits, Options... >::type
-                ,Options...
-            >::type   type;
-#   endif
-        };
-
-        //@cond
-        namespace details {
-            template <typename Node>
-            class head_node: public Node
-            {
-                typedef Node node_type;
-
-                typename node_type::atomic_marked_ptr   m_Tower[skip_list::c_nHeightLimit];
-
-            public:
-                head_node( unsigned int nHeight )
-                {
-                    for ( size_t i = 0; i < sizeof(m_Tower) / sizeof(m_Tower[0]); ++i )
-                        m_Tower[i].store( typename node_type::marked_ptr(), atomics::memory_order_relaxed );
-
-                    node_type::make_tower( nHeight, m_Tower );
-                }
-
-                node_type * head() const
-                {
-                    return const_cast<node_type *>( static_cast<node_type const *>(this));
-                }
-            };
-
-            template <typename NodeType, typename AtomicNodePtr, typename Alloc>
-            struct intrusive_node_builder
-            {
-                typedef NodeType        node_type;
-                typedef AtomicNodePtr   atomic_node_ptr;
-                typedef Alloc           allocator_type;
-
-                typedef cds::details::Allocator< atomic_node_ptr, allocator_type >  tower_allocator;
-
-                template <typename RandomGen>
-                static node_type * make_tower( node_type * pNode, RandomGen& gen )
-                {
-                    return make_tower( pNode, gen() + 1 );
-                }
-
-                static node_type * make_tower( node_type * pNode, unsigned int nHeight )
-                {
-                    if ( nHeight > 1 )
-                        pNode->make_tower( nHeight, tower_allocator().NewArray( nHeight - 1, nullptr ) );
-                    return pNode;
-                }
-
-                static void dispose_tower( node_type * pNode )
-                {
-                    unsigned int nHeight = pNode->height();
-                    if ( nHeight > 1 )
-                        tower_allocator().Delete( pNode->release_tower(), nHeight );
-                }
-
-                struct node_disposer {
-                    void operator()( node_type * pNode )
-                    {
-                        dispose_tower( pNode );
-                    }
-                };
-            };
-
-            // Forward declaration
-            template <class GC, typename NodeTraits, typename BackOff, bool IsConst>
-            class iterator;
-
-        } // namespace details
-        //@endcond
-
-    }   // namespace skip_list
-
-    // Forward declaration
-    template <class GC, typename T, typename Traits = skip_list::type_traits >
-    class SkipListSet;
-
-}}   // namespace cds::intrusive
-
-#endif // #ifndef __CDS_INTRUSIVE_SKIP_LIST_BASE_H
index 91e2acd4a4529d6139bf37b2c25b6349fbd8d078..034222a11f78dee91688e674842edba87bc0a89a 100644 (file)
@@ -5,7 +5,7 @@
 
 #include <type_traits>
 #include <memory>
-#include <cds/intrusive/skip_list_base.h>
+#include <cds/intrusive/details/skip_list_base.h>
 #include <cds/opt/compare.h>
 #include <cds/ref.h>
 #include <cds/details/binary_functor_wrapper.h>
index 5564479ee10fa1ba38658c584a14ef22e434e44b..cb1ca410a0a76b1e809aba916292eb2a97adfb3d 100644 (file)
@@ -6,7 +6,7 @@
 #include <type_traits>
 #include <memory>
 #include <cds/gc/nogc.h>
-#include <cds/intrusive/skip_list_base.h>
+#include <cds/intrusive/details/skip_list_base.h>
 #include <cds/opt/compare.h>
 #include <cds/ref.h>
 #include <cds/details/binary_functor_wrapper.h>
index 9d74a9741feb434da30f47ad6fcf1a5bab3c9e24..314d1700cbb767c285c560ead10222b92518f040 100644 (file)
@@ -5,7 +5,7 @@
 
 #include <type_traits>
 #include <memory>
-#include <cds/intrusive/skip_list_base.h>
+#include <cds/intrusive/details/skip_list_base.h>
 #include <cds/opt/compare.h>
 #include <cds/ref.h>
 #include <cds/urcu/details/check_deadlock.h>
index 6dbf8cbefaeb80e007c91ecae8aab72a233006ee..71c00816ef0aeff4d6c6724eb3f21a53fc991def 100644 (file)
     <ClInclude Include="..\..\..\cds\intrusive\details\node_traits.h" />\r
     <ClInclude Include="..\..\..\cds\intrusive\details\queue_stat.h" />\r
     <ClInclude Include="..\..\..\cds\intrusive\details\single_link_struct.h" />\r
+    <ClInclude Include="..\..\..\cds\intrusive\details\skip_list_base.h" />\r
     <ClInclude Include="..\..\..\cds\intrusive\ellen_bintree_hp.h" />\r
     <ClInclude Include="..\..\..\cds\intrusive\ellen_bintree_ptb.h" />\r
     <ClInclude Include="..\..\..\cds\intrusive\ellen_bintree_rcu.h" />\r
     <ClInclude Include="..\..\..\cds\intrusive\michael_set_rcu.h" />\r
     <ClInclude Include="..\..\..\cds\intrusive\mspriority_queue.h" />\r
     <ClInclude Include="..\..\..\cds\intrusive\options.h" />\r
-    <ClInclude Include="..\..\..\cds\intrusive\skip_list_base.h" />\r
     <ClInclude Include="..\..\..\cds\intrusive\skip_list_hp.h" />\r
     <ClInclude Include="..\..\..\cds\intrusive\skip_list_hrc.h" />\r
     <ClInclude Include="..\..\..\cds\intrusive\skip_list_impl.h" />\r
index 1571176487a2b80c7639cfe3f9e1cd9bd045e47c..7be01398e21cf0b07f20a3bcb0bf76a286abe41b 100644 (file)
     <ClInclude Include="..\..\..\cds\gc\exception.h">\r
       <Filter>Header Files\cds\gc</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="..\..\..\cds\intrusive\skip_list_base.h">\r
-      <Filter>Header Files\cds\intrusive</Filter>\r
-    </ClInclude>\r
     <ClInclude Include="..\..\..\cds\intrusive\skip_list_hp.h">\r
       <Filter>Header Files\cds\intrusive</Filter>\r
     </ClInclude>\r
     <ClInclude Include="..\..\..\cds\intrusive\details\queue_stat.h">\r
       <Filter>Header Files\cds\intrusive\details</Filter>\r
     </ClInclude>\r
+    <ClInclude Include="..\..\..\cds\intrusive\details\skip_list_base.h">\r
+      <Filter>Header Files\cds\intrusive\details</Filter>\r
+    </ClInclude>\r
   </ItemGroup>\r
 </Project>
\ No newline at end of file
index 4e8ec6fe5bbe00e5b1c16d806c105c85c93bc3de..7e40c1cc2dc3eb53ebc9e63899a417d243124547 100644 (file)
@@ -3,7 +3,7 @@
 #ifndef __UNIT_PRINT_SKIP_LIST_STAT_H
 #define __UNIT_PRINT_SKIP_LIST_STAT_H
 
-#include <cds/intrusive/skip_list_base.h>
+#include <cds/intrusive/details/skip_list_base.h>
 #include <ostream>
 
 namespace std {