mirror of https://github.com/ImVexed/muon.git
538 lines
11 KiB
C++
538 lines
11 KiB
C++
///
|
|
/// @file RefPtr.h
|
|
///
|
|
/// @brief The header for all ref-counting utilities.
|
|
///
|
|
/// @author
|
|
///
|
|
/// This file is a part of Ultralight, a fast, lightweight, HTML UI engine
|
|
///
|
|
/// Website: <http://ultralig.ht>
|
|
///
|
|
/// Copyright (C) 2019 Ultralight, Inc. All rights reserved.
|
|
///
|
|
/*
|
|
* Portions of the below code are derived from 'RefPtr.h' from Apple's WTF,
|
|
* with the following license header:
|
|
*
|
|
* Copyright (C) 2013-2014 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. AND ITS CONTRIBUTORS ``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 ITS 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 <Ultralight/Defines.h>
|
|
#include <assert.h>
|
|
#include <utility>
|
|
|
|
namespace ultralight {
|
|
|
|
///
|
|
/// @brief Interface for all ref-counted objects that will be managed using
|
|
/// the Ref<> and RefPtr<> smart pointers.
|
|
///
|
|
class UExport RefCounted {
|
|
public:
|
|
virtual void AddRef() const = 0;
|
|
virtual void Release() const = 0;
|
|
virtual int ref_count() const = 0;
|
|
protected:
|
|
virtual ~RefCounted();
|
|
};
|
|
|
|
inline void adopted(const void*) { }
|
|
|
|
template<typename T> class Ref;
|
|
|
|
///
|
|
/// @brief Helper for wrapping new objects with the Ref smart pointer.
|
|
///
|
|
/// All ref-counted object are created with an initial ref-count of '1'.
|
|
/// The AdoptRef() helper returns a Ref<T> without calling AddRef().
|
|
/// This is used for creating new objects, like so:
|
|
///
|
|
/// Ref<Object> ref = AdoptRef(*new ObjectImpl());
|
|
///
|
|
template<typename T> Ref<T> AdoptRef(T&);
|
|
|
|
///
|
|
/// @brief A non-nullable smart pointer.
|
|
///
|
|
/// This smart pointer automatically manages the lifetime of a RefCounted
|
|
/// object. Also guarantees that the managed instance is not NULL.
|
|
///
|
|
template<typename T> class Ref {
|
|
public:
|
|
///
|
|
/// Destroy Ref (wll decrement ref-count by one)
|
|
///
|
|
~Ref()
|
|
{
|
|
if (instance_)
|
|
instance_->Release();
|
|
}
|
|
|
|
///
|
|
/// Construct Ref from a reference. (Will increment ref-count by one)
|
|
///
|
|
Ref(T& object)
|
|
: instance_(&object)
|
|
{
|
|
instance_->AddRef();
|
|
}
|
|
|
|
///
|
|
/// Copy constructor.
|
|
///
|
|
Ref(const Ref& other)
|
|
: instance_(other.instance_)
|
|
{
|
|
instance_->AddRef();
|
|
}
|
|
|
|
///
|
|
/// Copy constructor with internal type conversion.
|
|
///
|
|
template<typename U>
|
|
Ref(Ref<U>& other)
|
|
: instance_(other.ptr())
|
|
{
|
|
instance_->AddRef();
|
|
}
|
|
|
|
///
|
|
/// Copy constructor with internal type conversion.
|
|
///
|
|
template<typename U>
|
|
Ref(const Ref<U>& other)
|
|
: instance_(other.ptr())
|
|
{
|
|
instance_->AddRef();
|
|
}
|
|
|
|
///
|
|
/// Move constructor.
|
|
///
|
|
Ref(Ref&& other)
|
|
: instance_(&other.LeakRef())
|
|
{
|
|
assert(instance_);
|
|
}
|
|
|
|
///
|
|
/// Move constructor.
|
|
///
|
|
template<typename U>
|
|
Ref(Ref<U>&& other)
|
|
: instance_(&other.LeakRef())
|
|
{
|
|
assert(instance_);
|
|
}
|
|
|
|
Ref& operator=(T& object)
|
|
{
|
|
assert(instance_);
|
|
object.AddRef();
|
|
instance_->Release();
|
|
instance_ = &object;
|
|
assert(instance_);
|
|
return *this;
|
|
}
|
|
|
|
Ref& operator=(const Ref& other)
|
|
{
|
|
assert(instance_);
|
|
other.instance_->AddRef();
|
|
instance_->Release();
|
|
instance_ = other.instance_;
|
|
assert(instance_);
|
|
return *this;
|
|
}
|
|
|
|
template<typename U>
|
|
Ref& operator=(const Ref<U>& other)
|
|
{
|
|
assert(instance_);
|
|
other.instance_->AddRef();
|
|
instance_->Release();
|
|
instance_ = other.instance_;
|
|
assert(instance_);
|
|
return *this;
|
|
}
|
|
|
|
Ref& operator=(Ref&& reference)
|
|
{
|
|
assert(instance_);
|
|
instance_->Release();
|
|
instance_ = &reference.LeakRef();
|
|
assert(instance_);
|
|
return *this;
|
|
}
|
|
|
|
template<typename U> Ref& operator=(Ref<U>&& reference)
|
|
{
|
|
assert(instance_);
|
|
instance_->Release();
|
|
instance_ = &reference.LeakRef();
|
|
assert(instance_);
|
|
return *this;
|
|
}
|
|
|
|
const T* operator->() const { assert(instance_); return instance_; }
|
|
T* operator->() { assert(instance_); return instance_; }
|
|
|
|
///
|
|
/// Get a pointer to wrapped object.
|
|
///
|
|
const T* ptr() const { assert(instance_); return instance_; }
|
|
|
|
///
|
|
/// Get a pointer to wrapped object.
|
|
///
|
|
T* ptr() { assert(instance_); return instance_; }
|
|
|
|
///
|
|
/// Get a reference to wrapped object.
|
|
///
|
|
const T& get() const { assert(instance_); return *instance_; }
|
|
|
|
///
|
|
/// Get a reference to wrapped object.
|
|
///
|
|
T& get() { assert(instance_); return *instance_; }
|
|
|
|
operator T&() { assert(instance_); return *instance_; }
|
|
operator const T&() const { assert(instance_); return *instance_; }
|
|
|
|
template<typename U> Ref<T> Replace(Ref<U>&&);
|
|
|
|
T& LeakRef() {
|
|
assert(instance_);
|
|
|
|
T* result = std::move(instance_);
|
|
instance_ = std::forward<T*>(nullptr);
|
|
return *result;
|
|
}
|
|
|
|
friend inline bool operator==(const Ref& a, const Ref& b) {
|
|
return a.instance_ == b.instance_;
|
|
}
|
|
|
|
friend inline bool operator!=(const Ref& a, const Ref& b) {
|
|
return a.instance_ != b.instance_;
|
|
}
|
|
|
|
friend inline bool operator<(const Ref& a, const Ref& b) {
|
|
return a.instance_ < b.instance_;
|
|
}
|
|
|
|
protected:
|
|
friend Ref AdoptRef<T>(T&);
|
|
template<typename U> friend class RefPtr;
|
|
|
|
enum AdoptTag { Adopt };
|
|
Ref(T& object, AdoptTag)
|
|
: instance_(&object)
|
|
{
|
|
}
|
|
|
|
T* instance_;
|
|
};
|
|
|
|
template<typename T> template<typename U> Ref<T> Ref<T>::Replace(Ref<U>&& reference)
|
|
{
|
|
auto oldReference = AdoptRef(*instance_);
|
|
instance_ = &reference.LeakRef();
|
|
return oldReference;
|
|
}
|
|
|
|
template<typename T>
|
|
Ref<T> AdoptRef(T& reference)
|
|
{
|
|
adopted(&reference);
|
|
return Ref<T>(reference, Ref<T>::Adopt);
|
|
}
|
|
|
|
///
|
|
/// @brief A nullable smart pointer.
|
|
///
|
|
/// This smart pointer automatically manages the lifetime of a RefCounted
|
|
/// object. The managed instance may be NULL.
|
|
///
|
|
template<typename T> class RefPtr {
|
|
public:
|
|
///
|
|
/// Construct a NULL ref-pointer.
|
|
///
|
|
RefPtr()
|
|
: instance_(nullptr)
|
|
{
|
|
}
|
|
|
|
///
|
|
/// Construct a NULL ref-pointer.
|
|
///
|
|
RefPtr(std::nullptr_t)
|
|
: instance_(nullptr)
|
|
{
|
|
}
|
|
|
|
///
|
|
/// Construct from a pointer. (Will increment ref-count by one)
|
|
///
|
|
RefPtr(T* other)
|
|
: instance_(other)
|
|
{
|
|
if (instance_)
|
|
instance_->AddRef();
|
|
}
|
|
|
|
///
|
|
/// Copy constructor.
|
|
///
|
|
RefPtr(const RefPtr& other)
|
|
: instance_(other.instance_)
|
|
{
|
|
if (instance_)
|
|
instance_->AddRef();
|
|
}
|
|
|
|
///
|
|
/// Copy constructor with internal type conversion.
|
|
///
|
|
template<typename U>
|
|
RefPtr(const RefPtr<U>& other)
|
|
: instance_(other.instance_)
|
|
{
|
|
if (instance_)
|
|
instance_->AddRef();
|
|
}
|
|
|
|
///
|
|
/// Move constructor.
|
|
///
|
|
RefPtr(RefPtr&& other)
|
|
: instance_(other.LeakRef())
|
|
{
|
|
}
|
|
|
|
///
|
|
/// Move constructor.
|
|
///
|
|
template<typename U>
|
|
RefPtr(RefPtr<U>&& other)
|
|
: instance_(other.LeakRef())
|
|
{
|
|
}
|
|
|
|
///
|
|
/// Construct from a Ref
|
|
///
|
|
template<typename U>
|
|
RefPtr(const Ref<U>& other)
|
|
: instance_(other.instance_)
|
|
{
|
|
if (instance_)
|
|
instance_->AddRef();
|
|
}
|
|
|
|
///
|
|
/// Construct by moving from a Ref
|
|
///
|
|
template<typename U>
|
|
RefPtr(Ref<U>&& other);
|
|
|
|
///
|
|
/// Destroy RefPtr (wll decrement ref-count by one)
|
|
///
|
|
~RefPtr()
|
|
{
|
|
T* old_value = std::move(instance_);
|
|
instance_ = std::forward<T*>(nullptr);
|
|
if (old_value)
|
|
old_value->Release();
|
|
}
|
|
|
|
///
|
|
/// Get a pointer to wrapped object.
|
|
///
|
|
T* get() const { return instance_; }
|
|
|
|
T* LeakRef() {
|
|
T* result = std::move(instance_);
|
|
instance_ = std::forward<T*>(nullptr);
|
|
return result;
|
|
}
|
|
|
|
T& operator*() const { assert(instance_); return *instance_; }
|
|
T* operator->() const { return instance_; }
|
|
|
|
bool operator!() const { return !instance_; }
|
|
|
|
// This conversion operator allows implicit conversion to bool but not to other integer types.
|
|
typedef T* (RefPtr::*UnspecifiedBoolType);
|
|
operator UnspecifiedBoolType() const { return instance_ ? &RefPtr::instance_ : nullptr; }
|
|
|
|
RefPtr& operator=(const RefPtr&);
|
|
RefPtr& operator=(T*);
|
|
RefPtr& operator=(std::nullptr_t);
|
|
template<typename U> RefPtr& operator=(const RefPtr<U>&);
|
|
RefPtr& operator=(RefPtr&&);
|
|
template<typename U> RefPtr& operator=(RefPtr<U>&&);
|
|
template<typename U> RefPtr& operator=(Ref<U>&&);
|
|
|
|
friend inline bool operator==(const RefPtr& a, const RefPtr& b) {
|
|
return a.instance_ == b.instance_;
|
|
}
|
|
|
|
friend inline bool operator!=(const RefPtr& a, const RefPtr& b) {
|
|
return a.instance_ != b.instance_;
|
|
}
|
|
|
|
friend inline bool operator<(const RefPtr& a, const RefPtr& b) {
|
|
return a.instance_ < b.instance_;
|
|
}
|
|
|
|
void Swap(RefPtr&);
|
|
|
|
private:
|
|
T* instance_;
|
|
};
|
|
|
|
template<typename T>
|
|
template<typename U>
|
|
RefPtr<T>::RefPtr(Ref<U>&& reference)
|
|
: instance_(&reference.LeakRef())
|
|
{
|
|
}
|
|
|
|
template<typename T>
|
|
RefPtr<T>& RefPtr<T>::operator=(const RefPtr& other)
|
|
{
|
|
RefPtr ptr = other;
|
|
Swap(ptr);
|
|
return *this;
|
|
}
|
|
|
|
template<typename T>
|
|
template<typename U>
|
|
RefPtr<T>& RefPtr<T>::operator=(const RefPtr<U>& other)
|
|
{
|
|
RefPtr ptr = other;
|
|
Swap(ptr);
|
|
return *this;
|
|
}
|
|
|
|
template<typename T>
|
|
RefPtr<T>& RefPtr<T>::operator=(T* object)
|
|
{
|
|
RefPtr ptr = object;
|
|
Swap(ptr);
|
|
return *this;
|
|
}
|
|
|
|
template<typename T>
|
|
RefPtr<T>& RefPtr<T>::operator=(std::nullptr_t)
|
|
{
|
|
T* old_instance = std::move(instance_);
|
|
instance_ = std::forward<T*>(nullptr);
|
|
if (old_instance)
|
|
old_instance->Release();
|
|
return *this;
|
|
}
|
|
|
|
template<typename T>
|
|
RefPtr<T>& RefPtr<T>::operator=(RefPtr&& other)
|
|
{
|
|
RefPtr ptr = std::move(other);
|
|
Swap(ptr);
|
|
return *this;
|
|
}
|
|
|
|
template<typename T>
|
|
template<typename U>
|
|
RefPtr<T>& RefPtr<T>::operator=(RefPtr<U>&& other)
|
|
{
|
|
RefPtr ptr = std::move(other);
|
|
Swap(ptr);
|
|
return *this;
|
|
}
|
|
|
|
template<typename T>
|
|
template<typename U>
|
|
RefPtr<T>& RefPtr<T>::operator=(Ref<U>&& other)
|
|
{
|
|
RefPtr ptr = std::move(other);
|
|
Swap(ptr);
|
|
return *this;
|
|
}
|
|
|
|
template<typename T>
|
|
void RefPtr<T>::Swap(RefPtr& other)
|
|
{
|
|
std::swap(instance_, other.instance_);
|
|
}
|
|
|
|
template<class T>
|
|
void Swap(RefPtr<T>& a, RefPtr<T>& b)
|
|
{
|
|
a.Swap(b);
|
|
}
|
|
|
|
template<typename T, typename U>
|
|
bool operator==(const RefPtr<T>& a, const RefPtr<U>& b)
|
|
{
|
|
return a.get() == b.get();
|
|
}
|
|
|
|
template<typename T, typename U>
|
|
bool operator==(const RefPtr<T>& a, U* b)
|
|
{
|
|
return a.get() == b;
|
|
}
|
|
|
|
template<typename T, typename U>
|
|
bool operator==(T* a, const RefPtr<U>& b)
|
|
{
|
|
return a == b.get();
|
|
}
|
|
|
|
template<typename T, typename U>
|
|
bool operator!=(const RefPtr<T>& a, const RefPtr<U>& b)
|
|
{
|
|
return a.get() != b.get();
|
|
}
|
|
|
|
template<typename T, typename U>
|
|
bool operator!=(const RefPtr<T>& a, U* b)
|
|
{
|
|
return a.get() != b;
|
|
}
|
|
|
|
template<typename T, typename U>
|
|
bool operator!=(T* a, const RefPtr<U>& b)
|
|
{
|
|
return a != b.get();
|
|
}
|
|
|
|
} // namespace ultralight
|