ladybird/AK/Weakable.h

133 lines
3.4 KiB
C
Raw Normal View History

/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
* 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT HOLDER 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.
*/
2018-10-13 13:41:24 +00:00
#pragma once
#include "Assertions.h"
#include "Atomic.h"
#include "RefCounted.h"
#include "RefPtr.h"
2018-10-13 13:41:24 +00:00
#ifndef WEAKABLE_DEBUG
# define WEAKABLE_DEBUG
#endif
2018-10-13 13:41:24 +00:00
namespace AK {
template<typename T>
class Weakable;
template<typename T>
class WeakPtr;
2018-10-13 13:41:24 +00:00
class WeakLink : public RefCounted<WeakLink> {
template<typename T>
friend class Weakable;
template<typename T>
friend class WeakPtr;
2018-10-13 13:41:24 +00:00
public:
template<typename T, typename PtrTraits = RefPtrTraits<T>>
RefPtr<T, PtrTraits> strong_ref() const
{
RefPtr<T, PtrTraits> ref;
{
#ifdef KERNEL
// We don't want to be pre-empted while we have the lock bit set
Kernel::ScopedCritical critical;
#endif
FlatPtr bits = RefPtrTraits<void>::lock(m_bits);
T* ptr = static_cast<T*>(RefPtrTraits<void>::as_ptr(bits));
if (ptr)
ref = *ptr;
RefPtrTraits<void>::unlock(m_bits, bits);
}
return ref;
}
template<typename T>
T* unsafe_ptr() const
{
return static_cast<T*>(RefPtrTraits<void>::as_ptr(m_bits.load(AK::MemoryOrder::memory_order_acquire)));
}
bool is_null() const
{
return RefPtrTraits<void>::is_null(m_bits.load(AK::MemoryOrder::memory_order_relaxed));
}
void revoke()
{
RefPtrTraits<void>::exchange(m_bits, RefPtrTraits<void>::default_null_value);
}
2018-10-13 13:41:24 +00:00
private:
template<typename T>
explicit WeakLink(T& weakable)
: m_bits(RefPtrTraits<void>::as_bits(&weakable))
{
}
mutable Atomic<FlatPtr> m_bits;
2018-10-13 13:41:24 +00:00
};
template<typename T>
class Weakable {
private:
class Link;
2018-10-13 13:41:24 +00:00
public:
template<typename U = T>
WeakPtr<U> make_weak_ptr() const;
2018-10-13 13:41:24 +00:00
protected:
Weakable() { }
2018-10-13 13:41:24 +00:00
~Weakable()
{
#ifdef WEAKABLE_DEBUG
m_being_destroyed = true;
#endif
revoke_weak_ptrs();
}
void revoke_weak_ptrs()
{
2018-10-13 13:41:24 +00:00
if (m_link)
m_link->revoke();
2018-10-13 13:41:24 +00:00
}
private:
mutable RefPtr<WeakLink> m_link;
#ifdef WEAKABLE_DEBUG
bool m_being_destroyed { false };
#endif
2018-10-13 13:41:24 +00:00
};
}
using AK::Weakable;