blob: e06a299528cbfb102d5a6a152d8b23b4bce9ada0 [file] [log] [blame]
/*
* Copyright (C) 2017-2018 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <cstddef>
#include <memory>
#include <wtf/FastMalloc.h>
#include <wtf/Poisoned.h>
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;
};
} // namespace WTF
using WTF::PoisonedUniquePtr;