#ifndef PMEMOBJ_PERSISTENT_PTR_HPP
#define PMEMOBJ_PERSISTENT_PTR_HPP
#include <cassert>
#include <limits>
#include <memory>
#include <ostream>
#include "libpmemobj++/detail/common.hpp"
#include "libpmemobj++/detail/persistent_ptr_base.hpp"
#include "libpmemobj++/detail/specialization.hpp"
#include "libpmemobj++/pool.hpp"
#include "libpmemobj.h"
namespace pmem
{
namespace obj
{
template <typename T>
class pool;
template <typename T>
class persistent_ptr;
template <>
class persistent_ptr<void> : public detail::persistent_ptr_base<void> {
public:
persistent_ptr() = default;
using detail::persistent_ptr_base<void>::persistent_ptr_base;
using detail::persistent_ptr_base<void>::operator=;
};
template <>
class persistent_ptr<const void>
: public detail::persistent_ptr_base<const void> {
public:
persistent_ptr() = default;
using detail::persistent_ptr_base<const void>::persistent_ptr_base;
using detail::persistent_ptr_base<const void>::operator=;
};
template <typename T>
class persistent_ptr : public detail::persistent_ptr_base<T> {
public:
persistent_ptr() = default;
using detail::persistent_ptr_base<T>::persistent_ptr_base;
explicit persistent_ptr(persistent_ptr<void> const &rhs) noexcept
: detail::persistent_ptr_base<T>(rhs.raw())
{
}
explicit persistent_ptr(persistent_ptr<const void> const &rhs) noexcept
: detail::persistent_ptr_base<T>(rhs.raw())
{
}
operator persistent_ptr<void>() const noexcept
{
return this->get();
}
typename pmem::detail::sp_dereference<T>::type operator*() const
noexcept
{
return *this->get();
}
typename pmem::detail::sp_member_access<T>::type operator->() const
noexcept
{
return this->get();
}
template <typename = typename std::enable_if<!std::is_void<T>::value>>
typename pmem::detail::sp_array_access<T>::type
operator[](std::ptrdiff_t i) const noexcept
{
assert(i >= 0 && (i < pmem::detail::sp_extent<T>::value ||
pmem::detail::sp_extent<T>::value == 0) &&
"persistent array index out of bounds");
return this->get()[i];
}
inline persistent_ptr<T> &operator++()
{
detail::conditional_add_to_tx(this);
this->oid.off += sizeof(T);
return *this;
}
inline persistent_ptr<T> operator++(int)
{
PMEMoid noid = this->oid;
++(*this);
return persistent_ptr<T>(noid);
}
inline persistent_ptr<T> &operator--()
{
detail::conditional_add_to_tx(this);
this->oid.off -= sizeof(T);
return *this;
}
inline persistent_ptr<T> operator--(int)
{
PMEMoid noid = this->oid;
--(*this);
return persistent_ptr<T>(noid);
}
inline persistent_ptr<T> &
operator+=(std::ptrdiff_t s)
{
detail::conditional_add_to_tx(this);
this->oid.off += s * sizeof(T);
return *this;
}
inline persistent_ptr<T> &
operator-=(std::ptrdiff_t s)
{
detail::conditional_add_to_tx(this);
this->oid.off -= s * sizeof(T);
return *this;
}
void
persist(pool_base &pop)
{
pop.persist(this->get(), sizeof(T));
}
void
persist(void)
{
pmemobjpool *pop = pmemobj_pool_by_oid(this->raw());
if (pop == nullptr)
throw pool_error("Cannot get pool from "
"persistent pointer");
pmemobj_persist(pop, this->get(), sizeof(T));
}
void
flush(pool_base &pop)
{
pop.flush(this->get(), sizeof(T));
}
void
flush(void)
{
pmemobjpool *pop = pmemobj_pool_by_oid(this->raw());
if (pop == nullptr)
throw pool_error("Cannot get pool from "
"persistent pointer");
pmemobj_flush(pop, this->get(), sizeof(T));
}
static persistent_ptr<T>
pointer_to(T &ref)
{
return persistent_ptr<T>(std::addressof(ref), 0);
}
template <class U>
using rebind = pmem::obj::persistent_ptr<U>;
using persistency_type = p<T>;
using bool_type = bool;
using iterator_category = std::random_access_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = T;
using reference = T &;
using pointer = persistent_ptr<T>;
};
template <class T>
inline void
swap(persistent_ptr<T> &a, persistent_ptr<T> &b)
{
a.swap(b);
}
template <typename T, typename Y>
inline bool
operator==(persistent_ptr<T> const &lhs, persistent_ptr<Y> const &rhs) noexcept
{
return OID_EQUALS(lhs.raw(), rhs.raw());
}
template <typename T, typename Y>
inline bool
operator!=(persistent_ptr<T> const &lhs, persistent_ptr<Y> const &rhs) noexcept
{
return !(lhs == rhs);
}
template <typename T>
inline bool
operator==(persistent_ptr<T> const &lhs, std::nullptr_t) noexcept
{
return lhs.get() == nullptr;
}
template <typename T>
inline bool
operator==(std::nullptr_t, persistent_ptr<T> const &lhs) noexcept
{
return lhs.get() == nullptr;
}
template <typename T>
inline bool
operator!=(persistent_ptr<T> const &lhs, std::nullptr_t) noexcept
{
return lhs.get() != nullptr;
}
template <typename T>
inline bool
operator!=(std::nullptr_t, persistent_ptr<T> const &lhs) noexcept
{
return lhs.get() != nullptr;
}
template <typename T, typename Y>
inline bool
operator<(persistent_ptr<T> const &lhs, persistent_ptr<Y> const &rhs) noexcept
{
if (lhs.raw().pool_uuid_lo == rhs.raw().pool_uuid_lo)
return lhs.raw().off < rhs.raw().off;
else
return lhs.raw().pool_uuid_lo < rhs.raw().pool_uuid_lo;
}
template <typename T, typename Y>
inline bool
operator<=(persistent_ptr<T> const &lhs, persistent_ptr<Y> const &rhs) noexcept
{
return !(rhs < lhs);
}
template <typename T, typename Y>
inline bool
operator>(persistent_ptr<T> const &lhs, persistent_ptr<Y> const &rhs) noexcept
{
return (rhs < lhs);
}
template <typename T, typename Y>
inline bool
operator>=(persistent_ptr<T> const &lhs, persistent_ptr<Y> const &rhs) noexcept
{
return !(lhs < rhs);
}
template <typename T>
inline bool
operator<(persistent_ptr<T> const &lhs, std::nullptr_t) noexcept
{
return std::less<typename persistent_ptr<T>::element_type *>()(
lhs.get(), nullptr);
}
template <typename T>
inline bool
operator<(std::nullptr_t, persistent_ptr<T> const &rhs) noexcept
{
return std::less<typename persistent_ptr<T>::element_type *>()(
nullptr, rhs.get());
}
template <typename T>
inline bool
operator<=(persistent_ptr<T> const &lhs, std::nullptr_t) noexcept
{
return !(nullptr < lhs);
}
template <typename T>
inline bool
operator<=(std::nullptr_t, persistent_ptr<T> const &rhs) noexcept
{
return !(rhs < nullptr);
}
template <typename T>
inline bool
operator>(persistent_ptr<T> const &lhs, std::nullptr_t) noexcept
{
return nullptr < lhs;
}
template <typename T>
inline bool
operator>(std::nullptr_t, persistent_ptr<T> const &rhs) noexcept
{
return rhs < nullptr;
}
template <typename T>
inline bool
operator>=(persistent_ptr<T> const &lhs, std::nullptr_t) noexcept
{
return !(lhs < nullptr);
}
template <typename T>
inline bool
operator>=(std::nullptr_t, persistent_ptr<T> const &rhs) noexcept
{
return !(nullptr < rhs);
}
template <typename T>
inline persistent_ptr<T>
operator+(persistent_ptr<T> const &lhs, std::ptrdiff_t s)
{
PMEMoid noid;
noid.pool_uuid_lo = lhs.raw().pool_uuid_lo;
noid.off = lhs.raw().off + (s * sizeof(T));
return persistent_ptr<T>(noid);
}
template <typename T>
inline persistent_ptr<T>
operator-(persistent_ptr<T> const &lhs, std::ptrdiff_t s)
{
PMEMoid noid;
noid.pool_uuid_lo = lhs.raw().pool_uuid_lo;
noid.off = lhs.raw().off - (s * sizeof(T));
return persistent_ptr<T>(noid);
}
template <typename T, typename Y,
typename = typename std::enable_if<
std::is_same<typename std::remove_cv<T>::type,
typename std::remove_cv<Y>::type>::value>>
inline ptrdiff_t
operator-(persistent_ptr<T> const &lhs, persistent_ptr<Y> const &rhs)
{
assert(lhs.raw().pool_uuid_lo == rhs.raw().pool_uuid_lo);
ptrdiff_t d = lhs.raw().off - rhs.raw().off;
return d / sizeof(T);
}
template <typename T>
std::ostream &
operator<<(std::ostream &os, persistent_ptr<T> const &pptr)
{
PMEMoid raw_oid = pptr.raw();
os << std::hex << "0x" << raw_oid.pool_uuid_lo << ", 0x" << raw_oid.off
<< std::dec;
return os;
}
}
}
#endif