1/*
2 * Copyright (C) 2010 Google 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 are
6 * met:
7 *
8 *     * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *     * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 *     * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#ifndef WebPrivatePtr_h
32#define WebPrivatePtr_h
33
34#include "WebCommon.h"
35
36#if INSIDE_BLINK
37#include "platform/heap/Handle.h"
38#include "wtf/PassRefPtr.h"
39#include "wtf/TypeTraits.h"
40#endif
41
42namespace blink {
43
44#if INSIDE_BLINK
45enum LifetimeManagementType {
46    RefCountedLifetime,
47    GarbageCollectedLifetime,
48    RefCountedGarbageCollectedLifetime
49};
50
51template<typename T>
52class LifetimeOf {
53    static const bool isGarbageCollected = WTF::IsSubclassOfTemplate<T, GarbageCollected>::value;
54    static const bool isRefCountedGarbageCollected = WTF::IsSubclassOfTemplate<T, RefCountedGarbageCollected>::value;
55public:
56    static const LifetimeManagementType value =
57        !isGarbageCollected ? RefCountedLifetime :
58        isRefCountedGarbageCollected ? RefCountedGarbageCollectedLifetime : GarbageCollectedLifetime;
59};
60
61template<typename T, LifetimeManagementType lifetime>
62class PtrStorageImpl;
63
64template<typename T>
65class PtrStorageImpl<T, RefCountedLifetime> {
66public:
67    typedef PassRefPtr<T> BlinkPtrType;
68
69    void assign(const BlinkPtrType& val)
70    {
71        release();
72        m_ptr = val.leakRef();
73    }
74
75    void assign(const PtrStorageImpl& other)
76    {
77        release();
78        T* val = other.get();
79        WTF::refIfNotNull(val);
80        m_ptr = val;
81    }
82
83    T* get() const { return m_ptr; }
84
85    void release()
86    {
87        WTF::derefIfNotNull(m_ptr);
88        m_ptr = 0;
89    }
90
91private:
92    T* m_ptr;
93};
94
95template<typename T>
96class PtrStorageImpl<T, GarbageCollectedLifetime> {
97public:
98    void assign(const RawPtr<T>& val)
99    {
100        if (!val) {
101            release();
102            return;
103        }
104
105        if (!m_handle)
106            m_handle = new Persistent<T>();
107
108        (*m_handle) = val;
109    }
110
111    void assign(T* ptr) { assign(RawPtr<T>(ptr)); }
112    template<typename U> void assign(const RawPtr<U>& val) { assign(RawPtr<T>(val)); }
113
114    void assign(const PtrStorageImpl& other) { assign(other.get()); }
115
116    T* get() const { return m_handle ? m_handle->get() : 0; }
117
118    void release()
119    {
120        delete m_handle;
121        m_handle = 0;
122    }
123
124private:
125    Persistent<T>* m_handle;
126};
127
128template<typename T>
129class PtrStorageImpl<T, RefCountedGarbageCollectedLifetime> : public PtrStorageImpl<T, GarbageCollectedLifetime> {
130public:
131    void assign(const PassRefPtrWillBeRawPtr<T>& val) { PtrStorageImpl<T, GarbageCollectedLifetime>::assign(val.get()); }
132
133    void assign(const PtrStorageImpl& other) { PtrStorageImpl<T, GarbageCollectedLifetime>::assign(other.get()); }
134};
135
136template<typename T>
137class PtrStorage : public PtrStorageImpl<T, LifetimeOf<T>::value> {
138public:
139    static PtrStorage& fromSlot(void** slot)
140    {
141        COMPILE_ASSERT(sizeof(PtrStorage) == sizeof(void*), PtrStorage_must_be_pointer_size);
142        return *reinterpret_cast<PtrStorage*>(slot);
143    }
144
145    static const PtrStorage& fromSlot(void* const* slot)
146    {
147        COMPILE_ASSERT(sizeof(PtrStorage) == sizeof(void*), PtrStorage_must_be_pointer_size);
148        return *reinterpret_cast<const PtrStorage*>(slot);
149    }
150
151private:
152    // Prevent construction via normal means.
153    PtrStorage();
154    PtrStorage(const PtrStorage&);
155};
156#endif
157
158
159// This class is an implementation detail of the Blink API. It exists to help
160// simplify the implementation of Blink interfaces that merely wrap a reference
161// counted WebCore class.
162//
163// A typical implementation of a class which uses WebPrivatePtr might look like
164// this:
165//    class WebFoo {
166//    public:
167//        BLINK_EXPORT ~WebFoo();
168//        WebFoo() { }
169//        WebFoo(const WebFoo& other) { assign(other); }
170//        WebFoo& operator=(const WebFoo& other)
171//        {
172//            assign(other);
173//            return *this;
174//        }
175//        BLINK_EXPORT void assign(const WebFoo&);  // Implemented in the body.
176//
177//        // Methods that are exposed to Chromium and which are specific to
178//        // WebFoo go here.
179//        BLINK_EXPORT doWebFooThing();
180//
181//        // Methods that are used only by other Blink classes should only be
182//        // declared when INSIDE_BLINK is set.
183//    #if INSIDE_BLINK
184//        WebFoo(const WTF::PassRefPtr<Foo>&);
185//    #endif
186//
187//    private:
188//        WebPrivatePtr<Foo> m_private;
189//    };
190//
191//    // WebFoo.cpp
192//    WebFoo::~WebFoo() { m_private.reset(); }
193//    void WebFoo::assign(const WebFoo& other) { ... }
194//
195template <typename T>
196class WebPrivatePtr {
197public:
198    WebPrivatePtr() : m_storage(0) { }
199    ~WebPrivatePtr()
200    {
201        // We don't destruct the object pointed by m_ptr here because we don't
202        // want to expose destructors of core classes to embedders. We should
203        // call reset() manually in destructors of classes with WebPrivatePtr
204        // members.
205        BLINK_ASSERT(!m_storage);
206    }
207
208    bool isNull() const { return !m_storage; }
209
210#if INSIDE_BLINK
211    template<typename U>
212    WebPrivatePtr(const U& ptr)
213        : m_storage(0)
214    {
215        storage().assign(ptr);
216    }
217
218    void reset() { storage().release(); }
219
220    WebPrivatePtr<T>& operator=(const WebPrivatePtr<T>& other)
221    {
222        storage().assign(other.storage());
223        return *this;
224    }
225
226    template<typename U>
227    WebPrivatePtr<T>& operator=(const U& ptr)
228    {
229        storage().assign(ptr);
230        return *this;
231    }
232
233    T* get() const { return storage().get(); }
234
235    T& operator*() const
236    {
237        ASSERT(m_storage);
238        return *get();
239    }
240
241    T* operator->() const
242    {
243        ASSERT(m_storage);
244        return get();
245    }
246#endif
247
248private:
249#if INSIDE_BLINK
250    PtrStorage<T>& storage() { return PtrStorage<T>::fromSlot(&m_storage); }
251    const PtrStorage<T>& storage() const { return PtrStorage<T>::fromSlot(&m_storage); }
252#endif
253
254#if !INSIDE_BLINK
255    // Disable the assignment operator; we define it above for when
256    // INSIDE_BLINK is set, but we need to make sure that it is not
257    // used outside there; the compiler-provided version won't handle reference
258    // counting properly.
259    WebPrivatePtr<T>& operator=(const WebPrivatePtr<T>& other);
260#endif
261    // Disable the copy constructor; classes that contain a WebPrivatePtr
262    // should implement their copy constructor using assign().
263    WebPrivatePtr(const WebPrivatePtr<T>&);
264
265    void* m_storage;
266};
267
268} // namespace blink
269
270#endif
271