|
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 #ifndef nsISupportsUtils_h__ |
|
7 #define nsISupportsUtils_h__ |
|
8 |
|
9 #include "nscore.h" |
|
10 #include "nsISupportsBase.h" |
|
11 #include "nsError.h" |
|
12 #include "nsDebug.h" |
|
13 #include "nsISupportsImpl.h" |
|
14 #include "mozilla/TypeTraits.h" |
|
15 |
|
16 /** |
|
17 * Macro for adding a reference to an interface. |
|
18 * @param _ptr The interface pointer. |
|
19 */ |
|
20 #define NS_ADDREF(_ptr) \ |
|
21 (_ptr)->AddRef() |
|
22 |
|
23 /** |
|
24 * Macro for adding a reference to this. This macro should be used |
|
25 * because NS_ADDREF (when tracing) may require an ambiguous cast |
|
26 * from the pointers primary type to nsISupports. This macro sidesteps |
|
27 * that entire problem. |
|
28 */ |
|
29 #define NS_ADDREF_THIS() \ |
|
30 AddRef() |
|
31 |
|
32 |
|
33 extern "C++" { |
|
34 // ...because some one is accidentally including this file inside |
|
35 // an |extern "C"| |
|
36 |
|
37 |
|
38 // Making this a |inline| |template| allows |expr| to be evaluated only once, |
|
39 // yet still denies you the ability to |AddRef()| an |nsCOMPtr|. |
|
40 template <class T> |
|
41 inline |
|
42 void |
|
43 ns_if_addref( T expr ) |
|
44 { |
|
45 if (expr) { |
|
46 expr->AddRef(); |
|
47 } |
|
48 } |
|
49 |
|
50 } /* extern "C++" */ |
|
51 |
|
52 /** |
|
53 * Macro for adding a reference to an interface that checks for nullptr. |
|
54 * @param _expr The interface pointer. |
|
55 */ |
|
56 #define NS_IF_ADDREF(_expr) ns_if_addref(_expr) |
|
57 |
|
58 /* |
|
59 * Given these declarations, it explicitly OK and efficient to end a `getter' with: |
|
60 * |
|
61 * NS_IF_ADDREF(*result = mThing); |
|
62 * |
|
63 * even if |mThing| is an |nsCOMPtr|. If |mThing| is an |nsCOMPtr|, however, it is still |
|
64 * _illegal_ to say |NS_IF_ADDREF(mThing)|. |
|
65 */ |
|
66 |
|
67 /** |
|
68 * Macro for releasing a reference to an interface. |
|
69 * @param _ptr The interface pointer. |
|
70 */ |
|
71 #define NS_RELEASE(_ptr) \ |
|
72 do { \ |
|
73 (_ptr)->Release(); \ |
|
74 (_ptr) = 0; \ |
|
75 } while (0) |
|
76 |
|
77 /** |
|
78 * Macro for releasing a reference to this interface. |
|
79 */ |
|
80 #define NS_RELEASE_THIS() \ |
|
81 Release() |
|
82 |
|
83 /** |
|
84 * Macro for releasing a reference to an interface, except that this |
|
85 * macro preserves the return value from the underlying Release call. |
|
86 * The interface pointer argument will only be NULLed if the reference count |
|
87 * goes to zero. |
|
88 * |
|
89 * @param _ptr The interface pointer. |
|
90 * @param _rc The reference count. |
|
91 */ |
|
92 #define NS_RELEASE2(_ptr, _rc) \ |
|
93 do { \ |
|
94 _rc = (_ptr)->Release(); \ |
|
95 if (0 == (_rc)) (_ptr) = 0; \ |
|
96 } while (0) |
|
97 |
|
98 /** |
|
99 * Macro for releasing a reference to an interface that checks for nullptr; |
|
100 * @param _ptr The interface pointer. |
|
101 */ |
|
102 #define NS_IF_RELEASE(_ptr) \ |
|
103 do { \ |
|
104 if (_ptr) { \ |
|
105 (_ptr)->Release(); \ |
|
106 (_ptr) = 0; \ |
|
107 } \ |
|
108 } while (0) |
|
109 |
|
110 /* |
|
111 * Often you have to cast an implementation pointer, e.g., |this|, to an |
|
112 * |nsISupports*|, but because you have multiple inheritance, a simple cast |
|
113 * is ambiguous. One could simply say, e.g., (given a base |nsIBase|), |
|
114 * |static_cast<nsIBase*>(this)|; but that disguises the fact that what |
|
115 * you are really doing is disambiguating the |nsISupports|. You could make |
|
116 * that more obvious with a double cast, e.g., |static_cast<nsISupports*> |
|
117 (* static_cast<nsIBase*>(this))|, but that is bulky and harder to read... |
|
118 * |
|
119 * The following macro is clean, short, and obvious. In the example above, |
|
120 * you would use it like this: |NS_ISUPPORTS_CAST(nsIBase*, this)|. |
|
121 */ |
|
122 |
|
123 #define NS_ISUPPORTS_CAST(__unambiguousBase, __expr) \ |
|
124 static_cast<nsISupports*>(static_cast<__unambiguousBase>(__expr)) |
|
125 |
|
126 // a type-safe shortcut for calling the |QueryInterface()| member function |
|
127 template <class T, class DestinationType> |
|
128 inline |
|
129 nsresult |
|
130 CallQueryInterface( T* aSource, DestinationType** aDestination ) |
|
131 { |
|
132 // We permit nsISupports-to-nsISupports here so that one can still obtain |
|
133 // the canonical nsISupports pointer with CallQueryInterface. |
|
134 static_assert(!mozilla::IsSame<T, DestinationType>::value || |
|
135 mozilla::IsSame<DestinationType, nsISupports>::value, |
|
136 "don't use CallQueryInterface for compile-time-determinable casts"); |
|
137 |
|
138 NS_PRECONDITION(aSource, "null parameter"); |
|
139 NS_PRECONDITION(aDestination, "null parameter"); |
|
140 |
|
141 return aSource->QueryInterface(NS_GET_TEMPLATE_IID(DestinationType), |
|
142 reinterpret_cast<void**>(aDestination)); |
|
143 } |
|
144 |
|
145 #endif /* __nsISupportsUtils_h */ |