Line data Source code
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
39 21468 : ns_if_addref(T aExpr)
40 : {
41 21468 : if (aExpr) {
42 18975 : aExpr->AddRef();
43 : }
44 21468 : }
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
123 59357 : 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 59357 : NS_PRECONDITION(aSource, "null parameter");
132 59357 : NS_PRECONDITION(aDestination, "null parameter");
133 :
134 : return aSource->QueryInterface(NS_GET_TEMPLATE_IID(DestinationType),
135 59357 : reinterpret_cast<void**>(aDestination));
136 : }
137 :
138 : template <class SourceType, class DestinationType>
139 : inline nsresult
140 0 : CallQueryInterface(RefPtr<SourceType>& aSourcePtr, DestinationType** aDestPtr)
141 : {
142 0 : return CallQueryInterface(aSourcePtr.get(), aDestPtr);
143 : }
144 :
145 : #endif /* __nsISupportsUtils_h */
|