PoisonedUniquePtr.h [plain text]
#pragma once
#include <wtf/FastMalloc.h>
#include <wtf/Poisoned.h>
#include <cstddef>
#include <memory>
namespace WTF {
template<typename Poison, typename T, typename Enable = void>
class PoisonedUniquePtr : public Poisoned<Poison, T*> {
WTF_MAKE_FAST_ALLOCATED;
using Base = Poisoned<Poison, T*>;
public:
static constexpr bool isPoisonedUniquePtrType = true;
using ValueType = T;
PoisonedUniquePtr() = default;
PoisonedUniquePtr(std::nullptr_t) : Base() { }
PoisonedUniquePtr(T* ptr) : Base(ptr) { }
PoisonedUniquePtr(PoisonedUniquePtr&& ptr) : Base(WTFMove(ptr)) { ptr.clearWithoutDestroy(); }
PoisonedUniquePtr(std::unique_ptr<T>&& unique) : PoisonedUniquePtr(unique.release()) { }
template<typename U, typename = std::enable_if_t<std::is_base_of<T, U>::value>>
PoisonedUniquePtr(std::unique_ptr<U>&& unique)
: Base(unique.release())
{ }
template<typename Other, typename = std::enable_if_t<Other::isPoisonedUniquePtrType && std::is_base_of<T, typename Other::ValueType>::value>>
PoisonedUniquePtr(Other&& ptr)
: Base(ptr.unpoisoned())
{
ptr.clearWithoutDestroy();
}
PoisonedUniquePtr(const PoisonedUniquePtr&) = delete;
~PoisonedUniquePtr() { destroy(); }
template<typename... Arguments>
static PoisonedUniquePtr create(Arguments&&... arguments)
{
return new T(std::forward<Arguments>(arguments)...);
}
PoisonedUniquePtr& operator=(T* ptr)
{
if (LIKELY(this->unpoisoned() != ptr)) {
this->clear();
this->Base::operator=(ptr);
}
return *this;
}
PoisonedUniquePtr& operator=(std::unique_ptr<T>&& unique)
{
this->clear();
this->Base::operator=(unique.release());
return *this;
}
template<typename U, typename = std::enable_if_t<std::is_base_of<T, U>::value>>
PoisonedUniquePtr& operator=(std::unique_ptr<U>&& unique)
{
this->clear();
this->Base::operator=(unique.release());
return *this;
}
template<typename Other, typename = std::enable_if_t<Other::isPoisonedUniquePtrType && std::is_base_of<T, typename Other::ValueType>::value>>
PoisonedUniquePtr& operator=(Other&& ptr)
{
ASSERT(this == static_cast<void*>(&ptr) || this->unpoisoned() != ptr.unpoisoned());
if (LIKELY(this != static_cast<void*>(&ptr))) {
this->clear();
this->Base::operator=(WTFMove(ptr));
ptr.clearWithoutDestroy();
}
return *this;
}
PoisonedUniquePtr& operator=(const PoisonedUniquePtr&) = delete;
T* get() const { return this->unpoisoned(); }
T& operator[](size_t index) const { return this->unpoisoned()[index]; }
void clear()
{
destroy();
clearWithoutDestroy();
}
private:
void destroy()
{
if (!this->bits())
return;
delete this->unpoisoned();
}
void clearWithoutDestroy() { Base::clear(); }
template<typename, typename, typename> friend class PoisonedUniquePtr;
};
template<typename Poison, typename T>
class PoisonedUniquePtr<Poison, T[]> : public Poisoned<Poison, T*> {
WTF_MAKE_FAST_ALLOCATED;
using Base = Poisoned<Poison, T*>;
public:
static constexpr bool isPoisonedUniquePtrType = true;
using ValueType = T[];
PoisonedUniquePtr() = default;
PoisonedUniquePtr(std::nullptr_t) : Base() { }
PoisonedUniquePtr(T* ptr) : Base(ptr) { }
PoisonedUniquePtr(PoisonedUniquePtr&& ptr) : Base(WTFMove(ptr)) { ptr.clearWithoutDestroy(); }
PoisonedUniquePtr(std::unique_ptr<T[]>&& unique) : PoisonedUniquePtr(unique.release()) { }
template<typename Other, typename = std::enable_if_t<Other::isPoisonedUniquePtrType && std::is_same<T[], typename Other::ValueType>::value>>
PoisonedUniquePtr(Other&& ptr)
: Base(ptr.unpoisoned())
{
ptr.clearWithoutDestroy();
}
PoisonedUniquePtr(const PoisonedUniquePtr&) = delete;
~PoisonedUniquePtr() { destroy(); }
template<typename... Arguments>
static PoisonedUniquePtr create(size_t count, Arguments&&... arguments)
{
T* result = new T[count];
while (count--)
new (result + count) T(std::forward<Arguments>(arguments)...);
return result;
}
PoisonedUniquePtr& operator=(T* ptr)
{
if (LIKELY(this->unpoisoned() != ptr)) {
this->clear();
this->Base::operator=(ptr);
}
return *this;
}
PoisonedUniquePtr& operator=(std::unique_ptr<T[]>&& unique)
{
this->clear();
this->Base::operator=(unique.release());
return *this;
}
template<typename Other, typename = std::enable_if_t<Other::isPoisonedUniquePtrType && std::is_same<T[], typename Other::ValueType>::value>>
PoisonedUniquePtr& operator=(Other&& ptr)
{
ASSERT(this == static_cast<void*>(&ptr) || this->unpoisoned() != ptr.unpoisoned());
if (LIKELY(this != static_cast<void*>(&ptr))) {
this->clear();
this->Base::operator=(WTFMove(ptr));
ptr.clearWithoutDestroy();
}
return *this;
}
PoisonedUniquePtr& operator=(const PoisonedUniquePtr&) = delete;
T* get() const { return this->unpoisoned(); }
T& operator[](size_t index) const { return this->unpoisoned()[index]; }
void clear()
{
destroy();
clearWithoutDestroy();
}
private:
void destroy()
{
if (!this->bits())
return;
delete[] this->unpoisoned();
}
void clearWithoutDestroy() { Base::clear(); }
template<typename, typename, typename> friend class PoisonedUniquePtr;
};
}
using WTF::PoisonedUniquePtr;