blob: e99e6bff6c5db77d85b23ab664212286abdb596e [file] [log] [blame]
// tagged pointer, for aba prevention
//
// Copyright (C) 2008, 2009 Tim Blechmann, based on code by Cory Nelson
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_LOCKFREE_TAGGED_PTR_PTRCOMPRESSION_HPP_INCLUDED
#define BOOST_LOCKFREE_TAGGED_PTR_PTRCOMPRESSION_HPP_INCLUDED
#include <cstddef> /* for std::size_t */
#include <limits>
#include <boost/cstdint.hpp>
#include <boost/lockfree/detail/branch_hints.hpp>
namespace boost {
namespace lockfree {
namespace detail {
#if defined (__x86_64__) || defined (_M_X64)
template <class T>
class tagged_ptr
{
typedef boost::uint64_t compressed_ptr_t;
public:
typedef boost::uint16_t tag_t;
private:
union cast_unit
{
compressed_ptr_t value;
tag_t tag[4];
};
static const int tag_index = 3;
static const compressed_ptr_t ptr_mask = 0xffffffffffffUL; //(1L<<48L)-1;
static T* extract_ptr(volatile compressed_ptr_t const & i)
{
return (T*)(i & ptr_mask);
}
static tag_t extract_tag(volatile compressed_ptr_t const & i)
{
cast_unit cu;
cu.value = i;
return cu.tag[tag_index];
}
static compressed_ptr_t pack_ptr(T * ptr, int tag)
{
cast_unit ret;
ret.value = compressed_ptr_t(ptr);
ret.tag[tag_index] = tag;
return ret.value;
}
public:
/** uninitialized constructor */
tagged_ptr(void) BOOST_NOEXCEPT//: ptr(0), tag(0)
{}
/** copy constructor */
#ifdef BOOST_NO_CXX11_DEFAULTED_FUNCTIONS
tagged_ptr(tagged_ptr const & p):
ptr(p.ptr)
{}
#else
tagged_ptr(tagged_ptr const & p) = default;
#endif
explicit tagged_ptr(T * p, tag_t t = 0):
ptr(pack_ptr(p, t))
{}
/** unsafe set operation */
/* @{ */
#ifdef BOOST_NO_CXX11_DEFAULTED_FUNCTIONS
tagged_ptr & operator= (tagged_ptr const & p)
{
ptr = p.ptr;
return *this;
}
#else
tagged_ptr & operator= (tagged_ptr const & p) = default;
#endif
void set(T * p, tag_t t)
{
ptr = pack_ptr(p, t);
}
/* @} */
/** comparing semantics */
/* @{ */
bool operator== (volatile tagged_ptr const & p) const
{
return (ptr == p.ptr);
}
bool operator!= (volatile tagged_ptr const & p) const
{
return !operator==(p);
}
/* @} */
/** pointer access */
/* @{ */
T * get_ptr() const
{
return extract_ptr(ptr);
}
void set_ptr(T * p)
{
tag_t tag = get_tag();
ptr = pack_ptr(p, tag);
}
/* @} */
/** tag access */
/* @{ */
tag_t get_tag() const
{
return extract_tag(ptr);
}
tag_t get_next_tag() const
{
tag_t next = (get_tag() + 1) & (std::numeric_limits<tag_t>::max)();
return next;
}
void set_tag(tag_t t)
{
T * p = get_ptr();
ptr = pack_ptr(p, t);
}
/* @} */
/** smart pointer support */
/* @{ */
T & operator*() const
{
return *get_ptr();
}
T * operator->() const
{
return get_ptr();
}
operator bool(void) const
{
return get_ptr() != 0;
}
/* @} */
protected:
compressed_ptr_t ptr;
};
#else
#error unsupported platform
#endif
} /* namespace detail */
} /* namespace lockfree */
} /* namespace boost */
#endif /* BOOST_LOCKFREE_TAGGED_PTR_PTRCOMPRESSION_HPP_INCLUDED */