1/*
2 * Copyright (C) 2013 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#ifndef DeferrableRefCounted_h
27#define DeferrableRefCounted_h
28
29#include <wtf/Assertions.h>
30#include <wtf/FastMalloc.h>
31#include <wtf/Noncopyable.h>
32
33namespace WTF {
34
35// A variant of RefCounted that allows reference counting to be deferred,
36// and can tell you if that has happened. You can think of a deferral as
37// just being an additional "ref", except that you can detect if it has
38// specifically happened - this can be useful either for debugging, or
39// sometimes even for some additional functionality.
40
41class DeferrableRefCountedBase {
42 static const unsigned deferredFlag = 1;
43 static const unsigned normalIncrement = 2;
44
45public:
46 void ref()
47 {
48 m_refCount += normalIncrement;
49 }
50
51 bool hasOneRef() const
52 {
53 return refCount() == 1;
54 }
55
56 unsigned refCount() const
57 {
58 return m_refCount / normalIncrement;
59 }
60
61 bool isDeferred() const
62 {
63 return !!(m_refCount & deferredFlag);
64 }
65
66protected:
67 DeferrableRefCountedBase()
68 : m_refCount(normalIncrement)
69 {
70 }
71
72 ~DeferrableRefCountedBase()
73 {
74 }
75
76 bool derefBase()
77 {
78 m_refCount -= normalIncrement;
79 return !m_refCount;
80 }
81
82 bool setIsDeferredBase(bool value)
83 {
84 if (value) {
85 m_refCount |= deferredFlag;
86 return false;
87 }
88 m_refCount &= ~deferredFlag;
89 return !m_refCount;
90 }
91
92private:
93 unsigned m_refCount;
94};
95
96template<typename T>
97class DeferrableRefCounted : public DeferrableRefCountedBase {
98 WTF_MAKE_NONCOPYABLE(DeferrableRefCounted); WTF_MAKE_FAST_ALLOCATED;
99public:
100 void deref()
101 {
102 if (derefBase())
103 delete static_cast<T*>(this);
104 }
105
106 bool setIsDeferred(bool value)
107 {
108 if (!setIsDeferredBase(value))
109 return false;
110 delete static_cast<T*>(this);
111 return true;
112 }
113
114protected:
115 DeferrableRefCounted() { }
116 ~DeferrableRefCounted() { }
117};
118
119} // namespace WTF
120
121using WTF::DeferrableRefCounted;
122
123#endif // DeferrableRefCounted_h
124
125