1 | /* |
2 | * Copyright (C) 2012 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 |
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 Supplementable_h |
27 | #define Supplementable_h |
28 | |
29 | #include <wtf/Assertions.h> |
30 | #include <wtf/HashMap.h> |
31 | #include <wtf/MainThread.h> |
32 | |
33 | #if !ASSERT_DISABLED |
34 | #include <wtf/Threading.h> |
35 | #endif |
36 | |
37 | namespace WebCore { |
38 | |
39 | // What you should know about Supplementable and Supplement |
40 | // ======================================================== |
41 | // Supplementable and Supplement instances are meant to be thread local. They |
42 | // should only be accessed from within the thread that created them. The |
43 | // 2 classes are not designed for safe access from another thread. Violating |
44 | // this design assumption can result in memory corruption and unpredictable |
45 | // behavior. |
46 | // |
47 | // What you should know about the Supplement keys |
48 | // ============================================== |
49 | // The Supplement is expected to use the same const char* string instance |
50 | // as its key. The Supplementable's SupplementMap will use the address of the |
51 | // string as the key and not the characters themselves. Hence, 2 strings with |
52 | // the same characters will be treated as 2 different keys. |
53 | // |
54 | // In practice, it is recommended that Supplements implements a static method |
55 | // for returning its key to use. For example: |
56 | // |
57 | // class MyClass : public Supplement<MySupplementable> { |
58 | // ... |
59 | // static const char* supplementName(); |
60 | // } |
61 | // |
62 | // const char* MyClass::supplementName() |
63 | // { |
64 | // return "MyClass"; |
65 | // } |
66 | // |
67 | // An example of the using the key: |
68 | // |
69 | // MyClass* MyClass::from(MySupplementable* host) |
70 | // { |
71 | // return reinterpret_cast<MyClass*>(Supplement<MySupplementable>::from(host, supplementName())); |
72 | // } |
73 | |
74 | template<typename T> |
75 | class Supplementable; |
76 | |
77 | template<typename T> |
78 | class Supplement { |
79 | public: |
80 | virtual ~Supplement() = default; |
81 | #if !ASSERT_DISABLED || ENABLE(SECURITY_ASSERTIONS) |
82 | virtual bool isRefCountedWrapper() const { return false; } |
83 | #endif |
84 | |
85 | static void provideTo(Supplementable<T>* host, const char* key, std::unique_ptr<Supplement<T>> supplement) |
86 | { |
87 | host->provideSupplement(key, WTFMove(supplement)); |
88 | } |
89 | |
90 | static Supplement<T>* from(Supplementable<T>* host, const char* key) |
91 | { |
92 | return host ? host->requireSupplement(key) : 0; |
93 | } |
94 | }; |
95 | |
96 | template<typename T> |
97 | class Supplementable { |
98 | public: |
99 | void provideSupplement(const char* key, std::unique_ptr<Supplement<T>> supplement) |
100 | { |
101 | ASSERT(canAccessThreadLocalDataForThread(m_thread.get())); |
102 | ASSERT(!m_supplements.get(key)); |
103 | m_supplements.set(key, WTFMove(supplement)); |
104 | } |
105 | |
106 | void removeSupplement(const char* key) |
107 | { |
108 | ASSERT(canAccessThreadLocalDataForThread(m_thread.get())); |
109 | m_supplements.remove(key); |
110 | } |
111 | |
112 | Supplement<T>* requireSupplement(const char* key) |
113 | { |
114 | ASSERT(canAccessThreadLocalDataForThread(m_thread.get())); |
115 | return m_supplements.get(key); |
116 | } |
117 | |
118 | #if !ASSERT_DISABLED |
119 | protected: |
120 | Supplementable() = default; |
121 | #endif |
122 | |
123 | private: |
124 | typedef HashMap<const char*, std::unique_ptr<Supplement<T>>, PtrHash<const char*>> SupplementMap; |
125 | SupplementMap m_supplements; |
126 | #if !ASSERT_DISABLED |
127 | Ref<Thread> m_thread { Thread::current() }; |
128 | #endif |
129 | }; |
130 | |
131 | } // namespace WebCore |
132 | |
133 | #endif // Supplementable_h |
134 | |
135 | |