#ifndef PMEMOBJ_ALLOCATOR_HPP
#define PMEMOBJ_ALLOCATOR_HPP
#include "libpmemobj++/detail/common.hpp"
#include "libpmemobj++/detail/life.hpp"
#include "libpmemobj++/detail/pexceptions.hpp"
#include "libpmemobj++/persistent_ptr.hpp"
#include "libpmemobj++/pext.hpp"
#include "libpmemobj.h"
namespace pmem
{
namespace obj
{
template <typename T>
class object_traits {
public:
using value_type = T;
using pointer = persistent_ptr<value_type>;
using const_pointer = persistent_ptr<const value_type>;
using reference = value_type &;
using const_reference = const value_type &;
template <class U>
struct rebind {
using other = object_traits<U>;
};
object_traits() = default;
~object_traits() = default;
template <typename U,
typename = typename std::enable_if<
std::is_convertible<U *, T *>::value>::type>
explicit object_traits(object_traits<U> const &)
{
}
void
construct(pointer p, const_reference t)
{
detail::conditional_add_to_tx(p.get());
new (static_cast<void *>(p.get())) value_type(t);
}
template <typename... Args>
void
construct(pointer p, Args &&... args)
{
detail::conditional_add_to_tx(p.get());
new (static_cast<void *>(p.get()))
value_type(std::forward<Args>(args)...);
}
void
destroy(pointer p)
{
if (pmemobj_tx_stage() == TX_STAGE_WORK) {
pmemobj_tx_add_range_direct((void *)p.get(), sizeof(p));
}
detail::destroy<value_type>(*p);
}
};
template <>
class object_traits<void> {
public:
using value_type = void;
using pointer = persistent_ptr<value_type>;
template <class U>
struct rebind {
using other = object_traits<U>;
};
object_traits() = default;
~object_traits() = default;
template <typename U>
explicit object_traits(object_traits<U> const &)
{
}
};
template <typename T>
class standard_alloc_policy {
public:
using value_type = T;
using pointer = persistent_ptr<value_type>;
using const_void_pointer = persistent_ptr<const void>;
using size_type = std::size_t;
using bool_type = bool;
template <class U>
struct rebind {
using other = standard_alloc_policy<U>;
};
standard_alloc_policy() = default;
~standard_alloc_policy() = default;
explicit standard_alloc_policy(standard_alloc_policy const &)
{
}
template <typename U,
typename = typename std::enable_if<
std::is_convertible<U *, T *>::value>::type>
explicit standard_alloc_policy(standard_alloc_policy<U> const &)
{
}
pointer
allocate(size_type cnt, const_void_pointer = 0)
{
if (pmemobj_tx_stage() != TX_STAGE_WORK)
throw transaction_scope_error(
"refusing to allocate "
"memory outside of transaction scope");
return pmemobj_tx_alloc(sizeof(value_type) * cnt,
detail::type_num<T>());
}
void
deallocate(pointer p, size_type = 0)
{
if (pmemobj_tx_stage() != TX_STAGE_WORK)
throw transaction_scope_error(
"refusing to free "
"memory outside of transaction scope");
if (pmemobj_tx_free(*p.raw_ptr()) != 0)
throw transaction_free_error(
"failed to delete "
"persistent memory object");
}
size_type
max_size() const
{
return PMEMOBJ_MAX_ALLOC_SIZE / sizeof(value_type);
}
};
template <>
class standard_alloc_policy<void> {
public:
using value_type = void;
using pointer = persistent_ptr<value_type>;
using const_pointer = persistent_ptr<const value_type>;
using reference = value_type;
using const_reference = const value_type;
using size_type = std::size_t;
using bool_type = bool;
template <class U>
struct rebind {
using other = standard_alloc_policy<U>;
};
standard_alloc_policy() = default;
~standard_alloc_policy() = default;
explicit standard_alloc_policy(standard_alloc_policy const &)
{
}
template <typename U>
explicit standard_alloc_policy(standard_alloc_policy<U> const &)
{
}
pointer
allocate(size_type cnt, const_pointer = 0)
{
if (pmemobj_tx_stage() != TX_STAGE_WORK)
throw transaction_scope_error(
"refusing to allocate "
"memory outside of transaction scope");
return pmemobj_tx_alloc(1 * cnt, 0);
}
void
deallocate(pointer p, size_type = 0)
{
if (pmemobj_tx_stage() != TX_STAGE_WORK)
throw transaction_scope_error(
"refusing to free "
"memory outside of transaction scope");
if (pmemobj_tx_free(p.raw()) != 0)
throw transaction_free_error(
"failed to delete "
"persistent memory object");
}
size_type
max_size() const
{
return PMEMOBJ_MAX_ALLOC_SIZE;
}
};
template <typename T, typename T2>
inline bool
operator==(standard_alloc_policy<T> const &, standard_alloc_policy<T2> const &)
{
return true;
}
template <typename T, typename OtherAllocator>
inline bool
operator==(standard_alloc_policy<T> const &, OtherAllocator const &)
{
return false;
}
template <typename T, typename Policy = standard_alloc_policy<T>,
typename Traits = object_traits<T>>
class allocator : public Policy, public Traits {
private:
using AllocationPolicy = Policy;
using TTraits = Traits;
public:
using size_type = typename AllocationPolicy::size_type;
using pointer = typename AllocationPolicy::pointer;
using value_type = typename AllocationPolicy::value_type;
template <typename U>
struct rebind {
using other = allocator<
U, typename AllocationPolicy::template rebind<U>::other,
typename TTraits::template rebind<U>::other>;
};
allocator() = default;
~allocator() = default;
explicit allocator(allocator const &rhs) : Policy(rhs), Traits(rhs)
{
}
template <typename U>
explicit allocator(allocator<U> const &)
{
}
template <typename U, typename P, typename T2>
explicit allocator(allocator<U, P, T2> const &rhs)
: Policy(rhs), Traits(rhs)
{
}
};
template <typename T, typename P, typename Tr, typename T2, typename P2,
typename Tr2>
inline bool
operator==(const allocator<T, P, Tr> &lhs, const allocator<T2, P2, Tr2> &rhs)
{
return operator==(static_cast<const P &>(lhs),
static_cast<const P2 &>(rhs));
}
template <typename T, typename P, typename Tr, typename OtherAllocator>
inline bool
operator!=(const allocator<T, P, Tr> &lhs, const OtherAllocator &rhs)
{
return !operator==(lhs, rhs);
}
}
}
#endif