Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Ready] Herlihy, Lev, Luchangco, Shavit A Provably Correct Scalable Concurrent Skip List #132

Open
wants to merge 3 commits into
base: integration
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
235 changes: 235 additions & 0 deletions cds/container/details/lazy_skip_list_base.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
#ifndef CDSLIB_CONTAINER_DETAILS_LAZY_SKIP_LIST_BASE_H
#define CDSLIB_CONTAINER_DETAILS_LAZY_SKIP_LIST_BASE_H

#include <cds/intrusive/details/lazy_skip_list_base.h>
#include <cds/container/details/base.h>
#include <memory>

namespace cds { namespace container {

namespace lazy_skip_list {
template <typename Type>
using random_level_generator = cds::intrusive::lazy_skip_list::random_level_generator<Type>;

template <unsigned MaxHeight>
using xor_shift = cds::intrusive::lazy_skip_list::xor_shift<MaxHeight >;

typedef cds::intrusive::lazy_skip_list::xorshift32 xorshift32;

typedef cds::intrusive::lazy_skip_list::xorshift24 xorshift24;

typedef cds::intrusive::lazy_skip_list::xorshift16 xorshift16;

using cds::intrusive::lazy_skip_list::xorshift;

template <unsigned MaxHeight>
using turbo = cds::intrusive::lazy_skip_list::turbo<MaxHeight >;

typedef cds::intrusive::lazy_skip_list::turbo32 turbo32;

typedef cds::intrusive::lazy_skip_list::turbo24 turbo24;

typedef cds::intrusive::lazy_skip_list::turbo16 turbo16;

using cds::intrusive::lazy_skip_list::turbo_pascal;

template <typename EventCounter = cds::atomicity::event_counter>
using stat = cds::intrusive::lazy_skip_list::stat < EventCounter >;

typedef cds::intrusive::lazy_skip_list::empty_stat empty_stat;

struct traits
{
typedef opt::none compare;
typedef opt::none less;
typedef atomicity::empty_item_counter item_counter;
typedef opt::v::relaxed_ordering memory_model;
typedef turbo32 random_level_generator;
typedef CDS_DEFAULT_ALLOCATOR allocator;
typedef cds::backoff::Default back_off;
typedef empty_stat stat;
typedef opt::none key_accessor;
};

template <typename... Options>
struct make_traits {
# ifdef CDS_DOXYGEN_INVOKED
typedef implementation_defined type ;
# else
typedef typename cds::opt::make_options<
typename cds::opt::find_type_traits< traits, Options... >::type
,Options...
>::type type;
# endif
};

namespace details {

template <typename Node, typename Traits>
class node_allocator
{
protected:
typedef Node node_type;
typedef Traits traits;

typedef typename node_type::tower_item_type node_tower_item;

typedef typename std::allocator_traits<typename traits::allocator>::template rebind_alloc<unsigned char> tower_allocator_type;
typedef typename std::allocator_traits<typename traits::allocator>::template rebind_alloc<node_type> node_allocator_type;

static size_t const c_nTowerItemSize = sizeof(node_tower_item);
static size_t const c_nNodePadding = sizeof(node_type) % c_nTowerItemSize;
static size_t const c_nNodeSize = sizeof(node_type) + (c_nNodePadding ? (c_nTowerItemSize - c_nNodePadding) : 0);

static constexpr size_t node_size( unsigned int nHeight ) noexcept
{
return c_nNodeSize + (nHeight - 1) * c_nTowerItemSize;
}

static unsigned char * alloc_space( unsigned int nHeight )
{
unsigned char * pMem;
size_t const sz = node_size( nHeight );

if ( nHeight > 1 ) {
pMem = tower_allocator_type().allocate( sz );

assert( (((uintptr_t) pMem) & (alignof(node_type) - 1)) == 0 );
assert( (((uintptr_t) (pMem + c_nNodeSize)) & (alignof(node_tower_item) - 1)) == 0 );
return pMem;
}
else
pMem = reinterpret_cast<unsigned char *>( node_allocator_type().allocate( 1 ));

return pMem;
}

static void free_space( unsigned char * p, unsigned int nHeight )
{
assert( p != nullptr );

if ( nHeight == 1 )
node_allocator_type().deallocate( reinterpret_cast<node_type *>(p), 1 );
else
tower_allocator_type().deallocate( p, node_size(nHeight));
}

public:
template <typename Q>
node_type * New( unsigned int nHeight, Q const& v )
{
unsigned char * pMem = alloc_space( nHeight );
node_type * p = new( pMem )
node_type( nHeight, nHeight > 1 ? reinterpret_cast<node_tower_item *>(pMem + c_nNodeSize) : nullptr, v );
return p;
}

template <typename... Args>
node_type * New( unsigned int nHeight, Args&&... args )
{
unsigned char * pMem = alloc_space( nHeight );
node_type * p = new( pMem )
node_type( nHeight, nHeight > 1 ? reinterpret_cast<node_tower_item *>(pMem + c_nNodeSize) : nullptr,
std::forward<Args>(args)... );
return p;
}

void Delete( node_type * p )
{
assert( p != nullptr );

unsigned int nHeight = p->height();
node_allocator_type a;
std::allocator_traits<node_allocator_type>::destroy( a, p );
free_space( reinterpret_cast<unsigned char *>(p), nHeight );
}
};

template <typename IntrusiveNode>
struct dummy_node_builder {
typedef IntrusiveNode intrusive_node_type;

template <typename RandomGen>
static intrusive_node_type * make_tower( intrusive_node_type * pNode, RandomGen& /*gen*/ ) { return pNode ; }
static intrusive_node_type * make_tower( intrusive_node_type * pNode, unsigned int /*nHeight*/ ) { return pNode ; }
static void dispose_tower( intrusive_node_type * pNode )
{
pNode->release_tower();
}

struct node_disposer {
void operator()( intrusive_node_type * /*pNode*/ ) const {}
};
};

template <typename ForwardIterator>
class iterator
{
typedef ForwardIterator intrusive_iterator;
typedef typename intrusive_iterator::value_type node_type;
typedef typename node_type::stored_value_type value_type;
static bool const c_isConst = intrusive_iterator::c_isConst;

typedef typename std::conditional< c_isConst, value_type const&, value_type&>::type value_ref;
template <typename FwdIt> friend class iterator;

intrusive_iterator m_It;

public: // for internal use only!!!
iterator( intrusive_iterator const& it )
: m_It( it )
{}

public:
iterator()
: m_It()
{}

iterator( iterator const& s)
: m_It( s.m_It )
{}

value_type * operator ->() const
{
return &( m_It.operator->()->m_Value );
}

value_ref operator *() const
{
return m_It.operator*().m_Value;
}

iterator& operator ++()
{
++m_It;
return *this;
}

iterator& operator = (iterator const& src)
{
m_It = src.m_It;
return *this;
}

template <typename FwIt>
bool operator ==(iterator<FwIt> const& i ) const
{
return m_It == i.m_It;
}
template <typename FwIt>
bool operator !=(iterator<FwIt> const& i ) const
{
return !( *this == i );
}
};

} // namespace details

} // namespace lazy_skip_list

template <class GC, typename T, typename Traits = lazy_skip_list::traits >
class LazySkipListSet;

}} // namespace cds::container

#endif // #ifndef CDSLIB_CONTAINER_DETAILS_LAZY_SKIP_LIST_BASE_H
89 changes: 89 additions & 0 deletions cds/container/details/make_lazy_skip_list_set.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#ifndef CDSLIB_CONTAINER_DETAILS_MAKE_LAZY_SKIP_LIST_SET_H
#define CDSLIB_CONTAINER_DETAILS_MAKE_LAZY_SKIP_LIST_SET_H

#include <cds/container/details/lazy_skip_list_base.h>
#include <cds/details/binary_functor_wrapper.h>

namespace cds { namespace container { namespace details {

template <typename GC, typename T, typename Traits>
struct make_lazy_skip_list_set
{
typedef GC gc;
typedef T value_type;
typedef Traits traits;

typedef cds::intrusive::lazy_skip_list::node< gc > intrusive_node_type;

struct node_type: public intrusive_node_type
{
typedef intrusive_node_type base_class;
typedef typename base_class::atomic_marked_ptr atomic_marked_ptr;
typedef value_type stored_value_type;

value_type m_Value;

template <typename Q>
node_type( unsigned int nHeight, atomic_marked_ptr * pTower, Q&& v )
: m_Value( std::forward<Q>( v ))
{
init_tower( nHeight, pTower );
}

template <typename Q, typename... Args>
node_type( unsigned int nHeight, atomic_marked_ptr * pTower, Q&& q, Args&&... args )
: m_Value( std::forward<Q>(q), std::forward<Args>(args)... )
{
init_tower( nHeight, pTower );
}

node_type() = delete;

private:
void init_tower( unsigned nHeight, atomic_marked_ptr* pTower )
{
if ( nHeight > 1 ) {
new ( pTower ) atomic_marked_ptr[nHeight - 1];
base_class::make_tower( nHeight, pTower );
}
}
};

typedef lazy_skip_list::details::node_allocator< node_type, traits> node_allocator;

struct node_deallocator {
void operator ()( node_type * pNode )
{
node_allocator().Delete( pNode );
}
};

typedef lazy_skip_list::details::dummy_node_builder<intrusive_node_type> dummy_node_builder;

struct value_accessor
{
value_type const& operator()( node_type const& node ) const
{
return node.m_Value;
}
};

typedef typename opt::details::make_comparator< value_type, traits >::type key_comparator;

template <typename Less>
using less_wrapper = cds::details::compare_wrapper< node_type, cds::opt::details::make_comparator_from_less<Less>, value_accessor >;

class intrusive_traits: public cds::intrusive::lazy_skip_list::make_traits<
cds::opt::type_traits< traits >
,cds::intrusive::opt::hook< intrusive::lazy_skip_list::base_hook< cds::opt::gc< gc > > >
,cds::intrusive::opt::disposer< node_deallocator >
,cds::intrusive::lazy_skip_list::internal_node_builder< dummy_node_builder >
,cds::opt::compare< cds::details::compare_wrapper< node_type, key_comparator, value_accessor > >
>::type
{};

typedef cds::intrusive::LazySkipListSet< gc, node_type, intrusive_traits> type;
};
}}} // namespace cds::container::details

#endif //#ifndef CDSLIB_CONTAINER_DETAILS_MAKE_LAZY_SKIP_LIST_SET_H
Loading