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