149 lines
4.1 KiB
C++
149 lines
4.1 KiB
C++
/*
|
|
* Copyright (C) 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 <wtf/Function.h>
|
|
#include <wtf/Noncopyable.h>
|
|
#include <wtf/RefPtr.h>
|
|
#include <wtf/SetForScope.h>
|
|
|
|
namespace WTF {
|
|
|
|
enum class RefCounterEvent { Decrement, Increment };
|
|
|
|
template<typename T>
|
|
class RefCounter {
|
|
WTF_MAKE_FAST_ALLOCATED;
|
|
WTF_MAKE_NONCOPYABLE(RefCounter);
|
|
|
|
class Count {
|
|
WTF_MAKE_NONCOPYABLE(Count);
|
|
public:
|
|
void ref();
|
|
void deref();
|
|
|
|
void refCounterWasDeleted();
|
|
|
|
private:
|
|
friend class RefCounter;
|
|
|
|
Count(RefCounter& refCounter)
|
|
: m_refCounter(&refCounter)
|
|
, m_value(0)
|
|
{
|
|
}
|
|
|
|
RefCounter* m_refCounter;
|
|
size_t m_value;
|
|
bool m_inValueDidChange { false };
|
|
};
|
|
|
|
public:
|
|
using Token = RefPtr<Count>;
|
|
using ValueChangeFunction = WTF::Function<void (RefCounterEvent)>;
|
|
|
|
RefCounter(ValueChangeFunction&& = nullptr);
|
|
~RefCounter();
|
|
|
|
Token count() const
|
|
{
|
|
return m_count;
|
|
}
|
|
|
|
size_t value() const
|
|
{
|
|
return m_count->m_value;
|
|
}
|
|
|
|
private:
|
|
ValueChangeFunction m_valueDidChange;
|
|
Count* m_count;
|
|
};
|
|
|
|
template<typename T>
|
|
inline void RefCounter<T>::Count::ref()
|
|
{
|
|
++m_value;
|
|
if (m_refCounter && m_refCounter->m_valueDidChange)
|
|
m_refCounter->m_valueDidChange(RefCounterEvent::Increment);
|
|
}
|
|
|
|
template<typename T>
|
|
inline void RefCounter<T>::Count::deref()
|
|
{
|
|
ASSERT(m_value);
|
|
|
|
--m_value;
|
|
|
|
if (m_refCounter && m_refCounter->m_valueDidChange) {
|
|
SetForScope<bool> inCallback(m_inValueDidChange, true);
|
|
m_refCounter->m_valueDidChange(RefCounterEvent::Decrement);
|
|
}
|
|
|
|
// The Count object is kept alive so long as either the RefCounter that created it remains
|
|
// allocated, or so long as its reference count is non-zero.
|
|
// If the RefCounter has already been deallocted then delete the Count when its reference
|
|
// count reaches zero.
|
|
if (!m_refCounter && !m_value)
|
|
delete this;
|
|
}
|
|
|
|
template<typename T>
|
|
inline void RefCounter<T>::Count::refCounterWasDeleted()
|
|
{
|
|
// The Count object is kept alive so long as either the RefCounter that created it remains
|
|
// allocated, or so long as its reference count is non-zero.
|
|
// If the reference count of the Count is already zero then delete it now, otherwise
|
|
// clear its m_refCounter pointer.
|
|
|
|
m_refCounter = nullptr;
|
|
|
|
if (m_inValueDidChange)
|
|
return;
|
|
|
|
if (!m_value)
|
|
delete this;
|
|
}
|
|
|
|
template<typename T>
|
|
inline RefCounter<T>::RefCounter(ValueChangeFunction&& valueDidChange)
|
|
: m_valueDidChange(WTFMove(valueDidChange))
|
|
, m_count(new Count(*this))
|
|
{
|
|
}
|
|
|
|
template<typename T>
|
|
inline RefCounter<T>::~RefCounter()
|
|
{
|
|
m_count->refCounterWasDeleted();
|
|
|
|
}
|
|
|
|
} // namespace WTF
|
|
|
|
using WTF::RefCounter;
|
|
using WTF::RefCounterEvent;
|