Bug 1867190 - Add prefs for PHC probablities r=glandium
[gecko.git] / xpcom / base / nsIClassInfoImpl.h
blob045e75e5aff9871972416cc165bd87ba41fc32c6
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/. */
7 #ifndef nsIClassInfoImpl_h__
8 #define nsIClassInfoImpl_h__
10 #include "mozilla/Alignment.h"
11 #include "mozilla/Assertions.h"
12 #include "mozilla/MacroArgs.h"
13 #include "mozilla/MacroForEach.h"
14 #include "nsIClassInfo.h"
15 #include "nsISupportsImpl.h"
17 #include <new>
19 /**
20 * This header file provides macros which help you make your class implement
21 * nsIClassInfo. Implementing nsIClassInfo is particularly helpful if you have
22 * a C++ class which implements multiple interfaces and which you access from
23 * JavaScript. If that class implements nsIClassInfo, the JavaScript code
24 * won't have to call QueryInterface on instances of the class; all methods
25 * from all interfaces returned by GetInterfaces() will be available
26 * automagically.
28 * Here's all you need to do. Given a class
30 * class nsFooBar : public nsIFoo, public nsIBar { };
32 * you should already have the following nsISupports implementation in its cpp
33 * file:
35 * NS_IMPL_ISUPPORTS(nsFooBar, nsIFoo, nsIBar).
37 * Change this to
39 * NS_IMPL_CLASSINFO(nsFooBar, nullptr, 0, NS_FOOBAR_CID)
40 * NS_IMPL_ISUPPORTS_CI(nsFooBar, nsIFoo, nsIBar)
42 * If nsFooBar is threadsafe, change the 0 above to nsIClassInfo::THREADSAFE.
43 * If it's a singleton, use nsIClassInfo::SINGLETON. The full list of flags is
44 * in nsIClassInfo.idl.
46 * The nullptr parameter is there so you can pass a function for converting
47 * from an XPCOM object to a scriptable helper. Unless you're doing
48 * specialized JS work, you can probably leave this as nullptr.
50 * This file also defines the NS_IMPL_QUERY_INTERFACE_CI macro, which you can
51 * use to replace NS_IMPL_QUERY_INTERFACE, if you use that instead of
52 * NS_IMPL_ISUPPORTS.
54 * That's it! The rest is gory details.
57 * Notice that nsFooBar didn't need to inherit from nsIClassInfo in order to
58 * "implement" it. However, after adding these macros to nsFooBar, you you can
59 * QueryInterface an instance of nsFooBar to nsIClassInfo. How can this be?
61 * The answer lies in the NS_IMPL_ISUPPORTS_CI macro. It modifies nsFooBar's
62 * QueryInterface implementation such that, if we ask to QI to nsIClassInfo, it
63 * returns a singleton object associated with the class. (That singleton is
64 * defined by NS_IMPL_CLASSINFO.) So all nsFooBar instances will return the
65 * same object when QI'ed to nsIClassInfo. (You can see this in
66 * NS_IMPL_QUERY_CLASSINFO below.)
68 * This hack breaks XPCOM's rules, since if you take an instance of nsFooBar,
69 * QI it to nsIClassInfo, and then try to QI to nsIFoo, that will fail. On the
70 * upside, implementing nsIClassInfo doesn't add a vtable pointer to instances
71 * of your class.
73 * In principal, you can also implement nsIClassInfo by inheriting from the
74 * interface. But some code expects that when it QI's an object to
75 * nsIClassInfo, it gets back a singleton which isn't attached to any
76 * particular object. If a class were to implement nsIClassInfo through
77 * inheritance, that code might QI to nsIClassInfo and keep the resulting
78 * object alive, thinking it was only keeping alive the classinfo singleton,
79 * but in fact keeping a whole instance of the class alive. See, e.g., bug
80 * 658632.
82 * Unless you specifically need to have a different nsIClassInfo instance for
83 * each instance of your class, you should probably just implement nsIClassInfo
84 * as a singleton.
87 class GenericClassInfo : public nsIClassInfo {
88 public:
89 struct ClassInfoData {
90 // This function pointer uses NS_CALLBACK_ because it's always set to an
91 // NS_IMETHOD function, which uses __stdcall on Win32.
92 typedef NS_CALLBACK_(nsresult, GetInterfacesProc)(nsTArray<nsIID>& aArray);
93 GetInterfacesProc getinterfaces;
95 // This function pointer doesn't use NS_CALLBACK_ because it's always set to
96 // a vanilla function.
97 typedef nsresult (*GetScriptableHelperProc)(nsIXPCScriptable** aHelper);
98 GetScriptableHelperProc getscriptablehelper;
100 uint32_t flags;
101 nsCID cid;
104 NS_DECL_ISUPPORTS_INHERITED
105 NS_DECL_NSICLASSINFO
107 explicit GenericClassInfo(const ClassInfoData* aData) : mData(aData) {}
109 private:
110 const ClassInfoData* mData;
113 #define NS_CLASSINFO_NAME(_class) g##_class##_classInfoGlobal
114 #define NS_CI_INTERFACE_GETTER_NAME(_class) _class##_GetInterfacesHelper
115 #define NS_DECL_CI_INTERFACE_GETTER(_class) \
116 extern NS_IMETHODIMP NS_CI_INTERFACE_GETTER_NAME(_class)(nsTArray<nsIID> & \
117 array);
119 #define NS_IMPL_CLASSINFO(_class, _getscriptablehelper, _flags, _cid) \
120 NS_DECL_CI_INTERFACE_GETTER(_class) \
121 static const GenericClassInfo::ClassInfoData k##_class##ClassInfoData = { \
122 NS_CI_INTERFACE_GETTER_NAME(_class), \
123 _getscriptablehelper, \
124 _flags | nsIClassInfo::SINGLETON_CLASSINFO, \
125 _cid, \
126 }; \
127 mozilla::AlignedStorage2<GenericClassInfo> k##_class##ClassInfoDataPlace; \
128 nsIClassInfo* NS_CLASSINFO_NAME(_class) = nullptr;
130 #define NS_IMPL_QUERY_CLASSINFO(_class) \
131 if (aIID.Equals(NS_GET_IID(nsIClassInfo))) { \
132 if (!NS_CLASSINFO_NAME(_class)) \
133 NS_CLASSINFO_NAME(_class) = new (k##_class##ClassInfoDataPlace.addr()) \
134 GenericClassInfo(&k##_class##ClassInfoData); \
135 foundInterface = NS_CLASSINFO_NAME(_class); \
136 } else
138 #define NS_CLASSINFO_HELPER_BEGIN(_class, _c) \
139 NS_IMETHODIMP \
140 NS_CI_INTERFACE_GETTER_NAME(_class)(nsTArray<nsIID> & array) { \
141 array.Clear(); \
142 array.SetCapacity(_c);
144 #define NS_CLASSINFO_HELPER_ENTRY(_interface) \
145 array.AppendElement(NS_GET_IID(_interface));
147 #define NS_CLASSINFO_HELPER_END \
148 return NS_OK; \
151 #define NS_IMPL_CI_INTERFACE_GETTER(aClass, ...) \
152 static_assert(MOZ_ARG_COUNT(__VA_ARGS__) > 0, \
153 "Need more arguments to NS_IMPL_CI_INTERFACE_GETTER"); \
154 NS_CLASSINFO_HELPER_BEGIN(aClass, MOZ_ARG_COUNT(__VA_ARGS__)) \
155 MOZ_FOR_EACH(NS_CLASSINFO_HELPER_ENTRY, (), (__VA_ARGS__)) \
156 NS_CLASSINFO_HELPER_END
158 #define NS_IMPL_CI_INTERFACE_GETTER0(aClass) \
159 NS_CLASSINFO_HELPER_BEGIN(aClass, 0) \
160 NS_CLASSINFO_HELPER_END
162 // Note that this macro is an internal implementation of this header and
163 // should not be used outside it. It does not end the interface map as this
164 // is done in NS_IMPL_QUERY_INTERFACE_CI or the _INHERITED variant.
165 #define NS_IMPL_QUERY_INTERFACE_CI_GUTS(aClass, ...) \
166 static_assert(MOZ_ARG_COUNT(__VA_ARGS__) > 0, \
167 "Need more arguments to NS_IMPL_QUERY_INTERFACE_CI"); \
168 NS_INTERFACE_MAP_BEGIN(aClass) \
169 MOZ_FOR_EACH(NS_INTERFACE_MAP_ENTRY, (), (__VA_ARGS__)) \
170 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, MOZ_ARG_1(__VA_ARGS__)) \
171 NS_IMPL_QUERY_CLASSINFO(aClass)
173 #define NS_IMPL_QUERY_INTERFACE_CI(aClass, ...) \
174 NS_IMPL_QUERY_INTERFACE_CI_GUTS(aClass, __VA_ARGS__) \
175 NS_INTERFACE_MAP_END
177 #define NS_IMPL_QUERY_INTERFACE_CI_INHERITED(aClass, aSuper, ...) \
178 NS_IMPL_QUERY_INTERFACE_CI_GUTS(aClass, __VA_ARGS__) \
179 NS_INTERFACE_MAP_END_INHERITING \
180 (aSuper)
182 #define NS_IMPL_QUERY_INTERFACE_CI_INHERITED0(aClass, aSuper) \
183 NS_INTERFACE_MAP_BEGIN(aClass) \
184 NS_IMPL_QUERY_CLASSINFO(aClass) \
185 NS_INTERFACE_MAP_END_INHERITING(aSuper)
187 #define NS_IMPL_ISUPPORTS_CI(aClass, ...) \
188 NS_IMPL_ADDREF(aClass) \
189 NS_IMPL_RELEASE(aClass) \
190 NS_IMPL_QUERY_INTERFACE_CI(aClass, __VA_ARGS__) \
191 NS_IMPL_CI_INTERFACE_GETTER(aClass, __VA_ARGS__)
193 #endif // nsIClassInfoImpl_h__