#ifndef PMEMOBJ_PERSISTENT_PTR_BASE_HPP
#define PMEMOBJ_PERSISTENT_PTR_BASE_HPP
#include <type_traits>
#include "libpmemobj++/detail/common.hpp"
#include "libpmemobj++/detail/specialization.hpp"
#include "libpmemobj.h"
#if defined(max) && defined(_WIN32)
#undef max
#endif
namespace pmem
{
namespace detail
{
template <typename T>
class persistent_ptr_base {
typedef persistent_ptr_base<T> this_type;
template <typename U>
friend class persistent_ptr_base;
public:
typedef typename pmem::detail::sp_element<T>::type element_type;
persistent_ptr_base() : oid(OID_NULL)
{
verify_type();
}
persistent_ptr_base(PMEMoid oid) noexcept : oid(oid)
{
verify_type();
}
persistent_ptr_base(element_type *ptr) : oid(pmemobj_oid(ptr))
{
verify_type();
}
template <typename U,
typename = typename std::enable_if<
!std::is_same<T, U>::value &&
std::is_same<typename std::remove_cv<T>::type,
U>::value>::type>
persistent_ptr_base(persistent_ptr_base<U> const &r) noexcept
: oid(r.oid)
{
this->oid.off += calculate_offset<U>();
verify_type();
}
template <
typename U, typename Dummy = void,
typename = typename std::enable_if<
!std::is_same<
typename std::remove_cv<T>::type,
typename std::remove_cv<U>::type>::value &&
!std::is_void<U>::value,
decltype(static_cast<T *>(std::declval<U *>()))>::type>
persistent_ptr_base(persistent_ptr_base<U> const &r) noexcept
: oid(r.oid)
{
this->oid.off += calculate_offset<U>();
verify_type();
}
template <
typename Y,
typename = typename std::enable_if<
!std::is_same<
typename std::remove_cv<T>::type,
typename std::remove_cv<Y>::type>::value &&
!std::is_void<Y>::value,
decltype(static_cast<T *>(std::declval<Y *>()))>::type>
operator persistent_ptr_base<Y>() noexcept
{
return persistent_ptr_base<Y>(this->oid);
}
persistent_ptr_base(persistent_ptr_base const &r) noexcept : oid(r.oid)
{
verify_type();
}
persistent_ptr_base(persistent_ptr_base &&r) noexcept
: oid(std::move(r.oid))
{
verify_type();
}
persistent_ptr_base &
operator=(persistent_ptr_base &&r)
{
detail::conditional_add_to_tx(this);
this->oid = std::move(r.oid);
return *this;
}
persistent_ptr_base &
operator=(persistent_ptr_base const &r)
{
this_type(r).swap(*this);
return *this;
}
persistent_ptr_base &
operator=(std::nullptr_t &&)
{
detail::conditional_add_to_tx(this);
this->oid = {0, 0};
return *this;
}
template <typename Y,
typename = typename std::enable_if<
std::is_convertible<Y *, T *>::value>::type>
persistent_ptr_base &
operator=(persistent_ptr_base<Y> const &r)
{
this_type(r).swap(*this);
return *this;
}
void
swap(persistent_ptr_base &other)
{
detail::conditional_add_to_tx(this);
detail::conditional_add_to_tx(&other);
std::swap(this->oid, other.oid);
}
element_type *
get() const noexcept
{
if (this->oid.pool_uuid_lo ==
std::numeric_limits<decltype(oid.pool_uuid_lo)>::max())
return reinterpret_cast<element_type *>(oid.off);
else
return static_cast<element_type *>(
pmemobj_direct(this->oid));
}
const PMEMoid &
raw() const noexcept
{
return this->oid;
}
PMEMoid *
raw_ptr() noexcept
{
return &(this->oid);
}
explicit operator bool() const noexcept
{
return get() != nullptr;
}
protected:
PMEMoid oid;
void
verify_type()
{
static_assert(!std::is_polymorphic<element_type>::value,
"Polymorphic types are not supported");
}
persistent_ptr_base(element_type *vptr, int) : persistent_ptr_base(vptr)
{
if (OID_IS_NULL(oid)) {
oid.pool_uuid_lo = std::numeric_limits<decltype(
oid.pool_uuid_lo)>::max();
oid.off = reinterpret_cast<decltype(oid.off)>(vptr);
}
}
template <typename U>
inline ptrdiff_t
calculate_offset() const
{
static const ptrdiff_t ptr_offset_magic = 0xDEADBEEF;
U *tmp{reinterpret_cast<U *>(ptr_offset_magic)};
T *diff = static_cast<T *>(tmp);
return reinterpret_cast<ptrdiff_t>(diff) -
reinterpret_cast<ptrdiff_t>(tmp);
}
};
}
}
#endif