xpcom/base/nsAgg.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/xpcom/base/nsAgg.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,331 @@
     1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#ifndef nsAgg_h___
    1.10 +#define nsAgg_h___
    1.11 +
    1.12 +#include "nsISupports.h"
    1.13 +#include "nsCycleCollectionParticipant.h"
    1.14 +
    1.15 +
    1.16 +////////////////////////////////////////////////////////////////////////////////
    1.17 +
    1.18 +// Put NS_DECL_AGGREGATED or NS_DECL_CYCLE_COLLECTING_AGGREGATED in your class's
    1.19 +// declaration.
    1.20 +#define NS_DECL_AGGREGATED                                                  \
    1.21 +    NS_DECL_ISUPPORTS                                                       \
    1.22 +    NS_DECL_AGGREGATED_HELPER
    1.23 +
    1.24 +#define NS_DECL_CYCLE_COLLECTING_AGGREGATED                                 \
    1.25 +    NS_DECL_CYCLE_COLLECTING_ISUPPORTS                                      \
    1.26 +    NS_DECL_AGGREGATED_HELPER
    1.27 +
    1.28 +#define NS_DECL_AGGREGATED_HELPER                                           \
    1.29 +public:                                                                     \
    1.30 +                                                                            \
    1.31 +    /**                                                                     \
    1.32 +     * Returns the nsISupports pointer of the inner object (aka the         \
    1.33 +     * aggregatee). This pointer is really only useful to the outer object  \
    1.34 +     * (aka the aggregator), which can use it to hold on to the inner       \
    1.35 +     * object. Anything else wants the nsISupports pointer of the outer     \
    1.36 +     * object (gotten by QI'ing inner or outer to nsISupports). This method \
    1.37 +     * returns a non-addrefed pointer.                                      \
    1.38 +     * @return the nsISupports pointer of the inner object                  \
    1.39 +     */                                                                     \
    1.40 +    nsISupports* InnerObject(void) { return &fAggregated; }                 \
    1.41 +                                                                            \
    1.42 +    /**                                                                     \
    1.43 +     * Returns true if this object is part of an aggregated object.      \
    1.44 +     */                                                                     \
    1.45 +    bool IsPartOfAggregated(void) { return fOuter != InnerObject(); }     \
    1.46 +                                                                            \
    1.47 +private:                                                                    \
    1.48 +                                                                            \
    1.49 +    /* You must implement this operation instead of the nsISupports */      \
    1.50 +    /* methods. */                                                          \
    1.51 +    nsresult                                                                \
    1.52 +    AggregatedQueryInterface(const nsIID& aIID, void** aInstancePtr);       \
    1.53 +                                                                            \
    1.54 +    class Internal : public nsISupports {                                   \
    1.55 +    public:                                                                 \
    1.56 +                                                                            \
    1.57 +        Internal() {}                                                       \
    1.58 +                                                                            \
    1.59 +        NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr);  \
    1.60 +        NS_IMETHOD_(MozExternalRefCountType) AddRef(void);                  \
    1.61 +        NS_IMETHOD_(MozExternalRefCountType) Release(void);                 \
    1.62 +                                                                            \
    1.63 +        NS_DECL_OWNINGTHREAD                                                \
    1.64 +    };                                                                      \
    1.65 +                                                                            \
    1.66 +    friend class Internal;                                                  \
    1.67 +                                                                            \
    1.68 +    nsISupports*        fOuter;                                             \
    1.69 +    Internal            fAggregated;                                        \
    1.70 +                                                                            \
    1.71 +public:                                                                     \
    1.72 +
    1.73 +#define NS_DECL_AGGREGATED_CYCLE_COLLECTION_CLASS(_class)                   \
    1.74 +class NS_CYCLE_COLLECTION_INNERCLASS                                        \
    1.75 + : public nsXPCOMCycleCollectionParticipant                                 \
    1.76 +{                                                                           \
    1.77 +public:                                                                     \
    1.78 +  NS_IMETHOD_(void) Unlink(void *p);                                        \
    1.79 +  NS_IMETHOD Traverse(void *p, nsCycleCollectionTraversalCallback &cb);     \
    1.80 +  NS_IMETHOD_(void) DeleteCycleCollectable(void* p)                         \
    1.81 +  {                                                                         \
    1.82 +    NS_CYCLE_COLLECTION_CLASSNAME(_class)::                                 \
    1.83 +      Downcast(static_cast<nsISupports*>(p))->DeleteCycleCollectable();     \
    1.84 +  }                                                                         \
    1.85 +  static _class* Downcast(nsISupports* s)                                   \
    1.86 +  {                                                                         \
    1.87 +    return (_class*)((char*)(s) - offsetof(_class, fAggregated));           \
    1.88 +  }                                                                         \
    1.89 +  static nsISupports* Upcast(_class *p)                                     \
    1.90 +  {                                                                         \
    1.91 +    return p->InnerObject();                                                \
    1.92 +  }                                                                         \
    1.93 +  static nsXPCOMCycleCollectionParticipant* GetParticipant()                \
    1.94 +  {                                                                         \
    1.95 +    return &_class::NS_CYCLE_COLLECTION_INNERNAME;                          \
    1.96 +  }                                                                         \
    1.97 +};                                                                          \
    1.98 +NS_CHECK_FOR_RIGHT_PARTICIPANT_IMPL(_class);                                \
    1.99 +static NS_CYCLE_COLLECTION_INNERCLASS NS_CYCLE_COLLECTION_INNERNAME;
   1.100 +
   1.101 +// Put this in your class's constructor:
   1.102 +#define NS_INIT_AGGREGATED(outer)                                           \
   1.103 +  PR_BEGIN_MACRO                                                            \
   1.104 +    fOuter = outer ? outer : &fAggregated;                                  \
   1.105 +  PR_END_MACRO
   1.106 +
   1.107 +
   1.108 +// Put this in your class's implementation file:
   1.109 +#define NS_IMPL_AGGREGATED(_class)                                          \
   1.110 +                                                                            \
   1.111 +NS_IMPL_AGGREGATED_HELPER(_class)                                           \
   1.112 +                                                                            \
   1.113 +NS_IMETHODIMP_(MozExternalRefCountType)                                     \
   1.114 +_class::Internal::AddRef(void)                                              \
   1.115 +{                                                                           \
   1.116 +    _class* agg = (_class*)((char*)(this) - offsetof(_class, fAggregated)); \
   1.117 +    MOZ_ASSERT(int32_t(agg->mRefCnt) >= 0, "illegal refcnt");               \
   1.118 +    NS_ASSERT_OWNINGTHREAD(_class);                                         \
   1.119 +    ++agg->mRefCnt;                                                         \
   1.120 +    NS_LOG_ADDREF(this, agg->mRefCnt, #_class, sizeof(*this));              \
   1.121 +    return agg->mRefCnt;                                                    \
   1.122 +}                                                                           \
   1.123 +                                                                            \
   1.124 +NS_IMETHODIMP_(MozExternalRefCountType)                                     \
   1.125 +_class::Internal::Release(void)                                             \
   1.126 +{                                                                           \
   1.127 +    _class* agg = (_class*)((char*)(this) - offsetof(_class, fAggregated)); \
   1.128 +    MOZ_ASSERT(int32_t(agg->mRefCnt) > 0, "dup release");                   \
   1.129 +    NS_ASSERT_OWNINGTHREAD(_class);                                         \
   1.130 +    --agg->mRefCnt;                                                         \
   1.131 +    NS_LOG_RELEASE(this, agg->mRefCnt, #_class);                            \
   1.132 +    if (agg->mRefCnt == 0) {                                                \
   1.133 +        agg->mRefCnt = 1; /* stabilize */                                   \
   1.134 +        delete agg;                                                         \
   1.135 +        return 0;                                                           \
   1.136 +    }                                                                       \
   1.137 +    return agg->mRefCnt;                                                    \
   1.138 +}                                                                           \
   1.139 +
   1.140 +#define NS_IMPL_CYCLE_COLLECTING_AGGREGATED(_class)                         \
   1.141 +                                                                            \
   1.142 +NS_IMPL_AGGREGATED_HELPER(_class)                                           \
   1.143 +                                                                            \
   1.144 +NS_IMETHODIMP_(MozExternalRefCountType)                                     \
   1.145 +_class::Internal::AddRef(void)                                              \
   1.146 +{                                                                           \
   1.147 +    _class* agg = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Downcast(this);    \
   1.148 +    MOZ_ASSERT(int32_t(agg->mRefCnt) >= 0, "illegal refcnt");               \
   1.149 +    NS_ASSERT_OWNINGTHREAD_AGGREGATE(agg, _class);                          \
   1.150 +    nsrefcnt count = agg->mRefCnt.incr(this);                               \
   1.151 +    NS_LOG_ADDREF(this, count, #_class, sizeof(*agg));                      \
   1.152 +    return count;                                                           \
   1.153 +}                                                                           \
   1.154 +NS_IMETHODIMP_(MozExternalRefCountType)                                     \
   1.155 +_class::Internal::Release(void)                                             \
   1.156 +{                                                                           \
   1.157 +    _class* agg = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Downcast(this);    \
   1.158 +    MOZ_ASSERT(int32_t(agg->mRefCnt) > 0, "dup release");                   \
   1.159 +    NS_ASSERT_OWNINGTHREAD_AGGREGATE(agg, _class);                          \
   1.160 +    nsrefcnt count = agg->mRefCnt.decr(this);                               \
   1.161 +    NS_LOG_RELEASE(this, count, #_class);                                   \
   1.162 +    return count;                                                           \
   1.163 +}                                                                           \
   1.164 +NS_IMETHODIMP_(void)                                                        \
   1.165 +_class::DeleteCycleCollectable(void)                                        \
   1.166 +{                                                                           \
   1.167 +  delete this;                                                              \
   1.168 +}
   1.169 +
   1.170 +#define NS_IMPL_AGGREGATED_HELPER(_class)                                   \
   1.171 +NS_IMETHODIMP                                                               \
   1.172 +_class::QueryInterface(const nsIID& aIID, void** aInstancePtr)              \
   1.173 +{                                                                           \
   1.174 +    return fOuter->QueryInterface(aIID, aInstancePtr);                      \
   1.175 +}                                                                           \
   1.176 +                                                                            \
   1.177 +NS_IMETHODIMP_(MozExternalRefCountType)                                     \
   1.178 +_class::AddRef(void)                                                        \
   1.179 +{                                                                           \
   1.180 +    return fOuter->AddRef();                                                \
   1.181 +}                                                                           \
   1.182 +                                                                            \
   1.183 +NS_IMETHODIMP_(MozExternalRefCountType)                                     \
   1.184 +_class::Release(void)                                                       \
   1.185 +{                                                                           \
   1.186 +    return fOuter->Release();                                               \
   1.187 +}                                                                           \
   1.188 +                                                                            \
   1.189 +NS_IMETHODIMP                                                               \
   1.190 +_class::Internal::QueryInterface(const nsIID& aIID, void** aInstancePtr)    \
   1.191 +{                                                                           \
   1.192 +    _class* agg = (_class*)((char*)(this) - offsetof(_class, fAggregated)); \
   1.193 +    return agg->AggregatedQueryInterface(aIID, aInstancePtr);               \
   1.194 +}                                                                           \
   1.195 +
   1.196 +/**
   1.197 + * To make aggregated objects participate in cycle collection we need to enable
   1.198 + * the outer object (aggregator) to traverse/unlink the objects held by the
   1.199 + * inner object (the aggregatee). We can't just make the inner object QI'able to
   1.200 + * NS_CYCLECOLLECTIONPARTICIPANT_IID, we don't want to return the inner object's
   1.201 + * nsCycleCollectionParticipant for the outer object (which will happen if the
   1.202 + * outer object doesn't participate in cycle collection itself).
   1.203 + * NS_AGGREGATED_CYCLECOLLECTIONPARTICIPANT_IID enables the outer object to get
   1.204 + * the inner objects nsCycleCollectionParticipant.
   1.205 + *
   1.206 + * There are three cases:
   1.207 + *   - No aggregation
   1.208 + *     QI'ing to NS_CYCLECOLLECTIONPARTICIPANT_IID will return the inner
   1.209 + *     object's nsCycleCollectionParticipant.
   1.210 + *
   1.211 + *   - Aggregation and outer object does not participate in cycle collection
   1.212 + *     QI'ing to NS_CYCLECOLLECTIONPARTICIPANT_IID will not return anything.
   1.213 + *
   1.214 + *   - Aggregation and outer object does participate in cycle collection
   1.215 + *     QI'ing to NS_CYCLECOLLECTIONPARTICIPANT_IID will return the outer
   1.216 + *     object's nsCycleCollectionParticipant. The outer object's
   1.217 + *     nsCycleCollectionParticipant can then QI the inner object to
   1.218 + *     NS_AGGREGATED_CYCLECOLLECTIONPARTICIPANT_IID to get the inner object's
   1.219 + *     nsCycleCollectionParticipant, which it can use to traverse/unlink the
   1.220 + *     objects reachable from the inner object.
   1.221 + */
   1.222 +#define NS_AGGREGATED_CYCLECOLLECTIONPARTICIPANT_IID                        \
   1.223 +{                                                                           \
   1.224 +    0x32889b7e,                                                             \
   1.225 +    0xe4fe,                                                                 \
   1.226 +    0x43f4,                                                                 \
   1.227 +    { 0x85, 0x31, 0xb5, 0x28, 0x23, 0xa2, 0xe9, 0xfc }                      \
   1.228 +}
   1.229 +
   1.230 +/**
   1.231 + * Just holds the IID so NS_GET_IID works.
   1.232 + */
   1.233 +class nsAggregatedCycleCollectionParticipant
   1.234 +{
   1.235 +public:
   1.236 +    NS_DECLARE_STATIC_IID_ACCESSOR(NS_AGGREGATED_CYCLECOLLECTIONPARTICIPANT_IID)
   1.237 +};
   1.238 +
   1.239 +NS_DEFINE_STATIC_IID_ACCESSOR(nsAggregatedCycleCollectionParticipant, 
   1.240 +                              NS_AGGREGATED_CYCLECOLLECTIONPARTICIPANT_IID)
   1.241 +
   1.242 +// for use with QI macros in nsISupportsUtils.h:
   1.243 +
   1.244 +#define NS_INTERFACE_MAP_BEGIN_AGGREGATED(_class)                           \
   1.245 +  NS_IMPL_AGGREGATED_QUERY_HEAD(_class)
   1.246 +
   1.247 +#define NS_INTERFACE_MAP_ENTRY_CYCLE_COLLECTION_AGGREGATED(_class)          \
   1.248 +  NS_IMPL_QUERY_CYCLE_COLLECTION(_class)
   1.249 +
   1.250 +#define NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION_AGGREGATED(_class)        \
   1.251 +  NS_INTERFACE_MAP_ENTRY_CYCLE_COLLECTION_AGGREGATED(_class)                \
   1.252 +  NS_INTERFACE_MAP_ENTRY_CYCLE_COLLECTION_ISUPPORTS(_class)
   1.253 +
   1.254 +#define NS_IMPL_AGGREGATED_QUERY_HEAD(_class)                               \
   1.255 +nsresult                                                                    \
   1.256 +_class::AggregatedQueryInterface(REFNSIID aIID, void** aInstancePtr)        \
   1.257 +{                                                                           \
   1.258 +  NS_ASSERTION(aInstancePtr,                                                \
   1.259 +               "AggregatedQueryInterface requires a non-NULL result ptr!"); \
   1.260 +  if ( !aInstancePtr )                                                      \
   1.261 +    return NS_ERROR_NULL_POINTER;                                           \
   1.262 +  nsISupports* foundInterface;                                              \
   1.263 +  if ( aIID.Equals(NS_GET_IID(nsISupports)) )                               \
   1.264 +    foundInterface = InnerObject();                                         \
   1.265 +  else
   1.266 +
   1.267 +#define NS_IMPL_AGGREGATED_QUERY_CYCLE_COLLECTION(_class)                   \
   1.268 +  if (aIID.Equals(IsPartOfAggregated() ?                                    \
   1.269 +                  NS_GET_IID(nsCycleCollectionParticipant) :                \
   1.270 +                  NS_GET_IID(nsAggregatedCycleCollectionParticipant)))      \
   1.271 +    foundInterface = NS_CYCLE_COLLECTION_PARTICIPANT(_class);               \
   1.272 +  else
   1.273 +
   1.274 +#define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_AGGREGATED(_class)          \
   1.275 +  NS_IMETHODIMP                                                             \
   1.276 +  NS_CYCLE_COLLECTION_CLASSNAME(_class)::Traverse                           \
   1.277 +                         (void *p, nsCycleCollectionTraversalCallback &cb)  \
   1.278 +  {                                                                         \
   1.279 +    nsISupports *s = static_cast<nsISupports*>(p);                          \
   1.280 +    MOZ_ASSERT(CheckForRightISupports(s),                                   \
   1.281 +               "not the nsISupports pointer we expect");                    \
   1.282 +    _class *tmp = static_cast<_class*>(Downcast(s));                        \
   1.283 +    if (!tmp->IsPartOfAggregated())                                         \
   1.284 +        NS_IMPL_CYCLE_COLLECTION_DESCRIBE(_class, tmp->mRefCnt.get())
   1.285 +
   1.286 +#define NS_GENERIC_AGGREGATED_CONSTRUCTOR(_InstanceClass)                   \
   1.287 +static nsresult                                                             \
   1.288 +_InstanceClass##Constructor(nsISupports *aOuter, REFNSIID aIID,             \
   1.289 +                            void **aResult)                                 \
   1.290 +{                                                                           \
   1.291 +    *aResult = nullptr;                                                     \
   1.292 +    if (NS_WARN_IF(aOuter && !aIID.Equals(NS_GET_IID(nsISupports))))        \
   1.293 +        return NS_ERROR_INVALID_ARG;                                        \
   1.294 +                                                                            \
   1.295 +    _InstanceClass* inst = new _InstanceClass(aOuter);                      \
   1.296 +    if (!inst) {                                                            \
   1.297 +        return NS_ERROR_OUT_OF_MEMORY;                                      \
   1.298 +    }                                                                       \
   1.299 +                                                                            \
   1.300 +    nsISupports* inner = inst->InnerObject();                               \
   1.301 +    nsresult rv = inner->QueryInterface(aIID, aResult);                     \
   1.302 +    if (NS_FAILED(rv)) {                                                    \
   1.303 +        delete inst;                                                        \
   1.304 +    }                                                                       \
   1.305 +                                                                            \
   1.306 +    return rv;                                                              \
   1.307 +}                                                                           \
   1.308 +
   1.309 +#define NS_GENERIC_AGGREGATED_CONSTRUCTOR_INIT(_InstanceClass, _InitMethod) \
   1.310 +static nsresult                                                             \
   1.311 +_InstanceClass##Constructor(nsISupports *aOuter, REFNSIID aIID,             \
   1.312 +                            void **aResult)                                 \
   1.313 +{                                                                           \
   1.314 +    *aResult = nullptr;                                                     \
   1.315 +    if (NS_WARN_IF(aOuter && !aIID.Equals(NS_GET_IID(nsISupports))))        \
   1.316 +        return NS_ERROR_INVALID_ARG;                                        \
   1.317 +                                                                            \
   1.318 +    _InstanceClass* inst = new _InstanceClass(aOuter);                      \
   1.319 +    if (!inst) {                                                            \
   1.320 +        return NS_ERROR_OUT_OF_MEMORY;                                      \
   1.321 +    }                                                                       \
   1.322 +                                                                            \
   1.323 +    nsISupports* inner = inst->InnerObject();                               \
   1.324 +    NS_ADDREF(inner);                                                       \
   1.325 +    nsresult rv = inst->_InitMethod();                                      \
   1.326 +    if (NS_SUCCEEDED(rv)) {                                                 \
   1.327 +        rv = inner->QueryInterface(aIID, aResult);                          \
   1.328 +    }                                                                       \
   1.329 +    NS_RELEASE(inner);                                                      \
   1.330 +                                                                            \
   1.331 +    return rv;                                                              \
   1.332 +}                                                                           \
   1.333 +
   1.334 +#endif /* nsAgg_h___ */

mercurial